Skip to content

Moved sentry logging to a monolog handler #165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8a28d6c
Moved sentry logging to a monolog handler
indykoning Apr 9, 2025
f636545
Apply fixes from StyleCI
StyleCIBot Apr 9, 2025
00a5b12
Merge pull request #163 from justbetter/analysis-54MD5B
royduin Apr 9, 2025
61fda24
Codestyle fixes
indykoning Apr 9, 2025
c207bb8
Merge branch 'feature/monolog-handler' of github.com:justbetter/magen…
indykoning Apr 9, 2025
7e03caf
Apply fixes from StyleCI
StyleCIBot Apr 9, 2025
9f46233
Merge pull request #164 from justbetter/analysis-YOGZ7y
royduin Apr 9, 2025
4ab0408
Removed explicit type cast
indykoning Apr 9, 2025
90e26bc
Merge branch 'feature/monolog-handler' of github.com:justbetter/magen…
indykoning Apr 9, 2025
8d2722c
Removed expected type for ishandling and handle
indykoning Apr 9, 2025
1b669da
Added a logger api check for backward and forward compatibility
indykoning Apr 9, 2025
a195a2b
Check if log level is set before overriding
indykoning Apr 10, 2025
2e31b73
Use prefer lowest and prefer stable for checks, fixed phpstan
indykoning Apr 22, 2025
2a2dbda
Apply fixes from StyleCI
StyleCIBot Apr 22, 2025
107c88e
Merge pull request #166 from justbetter/analysis-01GL4M
royduin Apr 22, 2025
98a7d74
Added dependency on CSP module
indykoning Apr 22, 2025
652527f
Merge branch 'feature/monolog-handler' of github.com:justbetter/magen…
indykoning Apr 22, 2025
28cdf1b
Added monolog context as EventHint
indykoning Apr 22, 2025
62deffc
Apply fixes from StyleCI
StyleCIBot Apr 22, 2025
dc344ae
Merge pull request #167 from justbetter/analysis-KonVnA
royduin Apr 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
**Checklist**

- [ ] I've ran `composer run codestyle`
- [ ] I've ran `composer run phpstan`
- [ ] I've ran `composer run analyse`
12 changes: 9 additions & 3 deletions .github/workflows/analyse.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ on:
jobs:
test:
runs-on: ubuntu-latest
name: analyse
strategy:
fail-fast: true
matrix:
php: [8.2, 8.3]
stability: [prefer-lowest, prefer-stable]

name: PHPStan - P${{ matrix.php }} - ${{ matrix.stability }}

steps:
- name: Checkout code
Expand All @@ -18,12 +24,12 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
coverage: none

- name: Install dependencies
run: composer install --no-interaction
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction

- name: Analyse
run: composer run analyse
12 changes: 9 additions & 3 deletions .github/workflows/php.yml → .github/workflows/phpcs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ on:
jobs:
test:
runs-on: ubuntu-latest
name: PHPCS
strategy:
fail-fast: true
matrix:
php: [8.2, 8.3]
stability: [prefer-lowest, prefer-stable]

name: PHPCS - P${{ matrix.php }} - ${{ matrix.stability }}

steps:
- name: Checkout code
Expand All @@ -18,12 +24,12 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
coverage: none

- name: Install dependencies
run: composer install --no-interaction
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction

- name: Analyse
run: composer run phpcs
2 changes: 1 addition & 1 deletion Helper/Version.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Version extends AbstractHelper
public function __construct(
private \Magento\Framework\App\State $appState,
private \Magento\Framework\App\View\Deployment\Version\StorageInterface $versionStorage,
DeploymentConfig $deploymentConfig = null
?DeploymentConfig $deploymentConfig = null
) {
$this->deploymentConfig = $deploymentConfig ?: ObjectManager::getInstance()->get(DeploymentConfig::class);
}
Expand Down
105 changes: 105 additions & 0 deletions Logger/Handler/Sentry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

namespace JustBetter\Sentry\Logger\Handler;

use JustBetter\Sentry\Helper\Data;
use JustBetter\Sentry\Model\SentryLog;
use Magento\Framework\App\DeploymentConfig;
use Monolog\Handler\AbstractHandler;
use Monolog\Logger;
use Monolog\LogRecord;

// TODO: Remove once V2 support is dropped.
// phpcs:disable Generic.Classes.DuplicateClassName,PSR2.Classes.ClassDeclaration,PSR1.Classes.ClassDeclaration.MultipleClasses
if (Logger::API < 3) {
class Sentry extends AbstractHandler
{
/**
* Construct.
*
* @param Data $sentryHelper
* @param SentryLog $sentryLog
* @param DeploymentConfig $deploymentConfig
*/
public function __construct(
protected Data $sentryHelper,
protected SentryLog $sentryLog,
protected DeploymentConfig $deploymentConfig,
) {
parent::__construct();
}

/**
* @inheritDoc
*/
public function isHandling(array $record): bool
{
$config = $this->sentryHelper->collectModuleConfig();
if ($config['log_level']) {
$this->setLevel($config['log_level']);
}

return parent::isHandling($record) && $this->deploymentConfig->isAvailable() && $this->sentryHelper->isActive();
}

/**
* @inheritDoc
*/
public function handle(array $record): bool
{
if (!$this->isHandling($record)) {
return false;
}

$this->sentryLog->send($record['message'], $record['level'], $record['context']);

return false;
}
}
} else {
class Sentry extends AbstractHandler
{
/**
* Construct.
*
* @param Data $sentryHelper
* @param SentryLog $sentryLog
* @param DeploymentConfig $deploymentConfig
*/
public function __construct(
protected Data $sentryHelper,
protected SentryLog $sentryLog,
protected DeploymentConfig $deploymentConfig,
) {
parent::__construct();
}

/**
* @inheritDoc
*/
public function isHandling(LogRecord $record): bool
{
$config = $this->sentryHelper->collectModuleConfig();
if ($config['log_level']) {
$this->setLevel($config['log_level']);
}

return parent::isHandling($record) && $this->deploymentConfig->isAvailable() && $this->sentryHelper->isActive();
}

/**
* @inheritDoc
*/
public function handle(LogRecord $record): bool
{
if (!$this->isHandling($record)) {
return false;
}

$this->sentryLog->send($record['message'], $record['level'], $record['context']);

return false;
}
}
}
// phpcs:enable Generic.Classes.DuplicateClassName,PSR2.Classes.ClassDeclaration,PSR1.Classes.ClassDeclaration.MultipleClasses
42 changes: 32 additions & 10 deletions Model/SentryLog.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
use Magento\Framework\App\State;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\SessionException;
use Magento\Framework\Logger\Monolog;
use Sentry\EventHint;
use Sentry\ExceptionMechanism;
use Sentry\Stacktrace;
use Sentry\State\Scope as SentryScope;

class SentryLog extends Monolog
class SentryLog
{
/**
* @var array
Expand All @@ -21,24 +23,17 @@ class SentryLog extends Monolog
/**
* SentryLog constructor.
*
* @param string $name
* @param Data $data
* @param Session $customerSession
* @param State $appState
* @param SentryInteraction $sentryInteraction
* @param array $handlers
* @param array $processors
*/
public function __construct(
$name,
protected Data $data,
protected Session $customerSession,
private State $appState,
private SentryInteraction $sentryInteraction,
array $handlers = [],
array $processors = []
) {
parent::__construct($name, $handlers, $processors);
}

/**
Expand Down Expand Up @@ -76,7 +71,11 @@ function (SentryScope $scope) use ($context, $customTags): void {
if ($message instanceof \Throwable) {
$lastEventId = \Sentry\captureException($message);
} else {
$lastEventId = \Sentry\captureMessage($message, \Sentry\Severity::fromError($logLevel));
$lastEventId = \Sentry\captureMessage(
$message,
\Sentry\Severity::fromError($logLevel),
$this->monologContextToSentryHint($context)
);
}

/// when using JS SDK you can use this for custom error page printing
Expand All @@ -89,6 +88,29 @@ function (SentryScope $scope) use ($context, $customTags): void {
}
}

/**
* Turn the monolog context into a format Sentrys EventHint can deal with.
*
* @param array $context
*
* @return EventHint|null
*/
public function monologContextToSentryHint(array $context): ?EventHint
{
return EventHint::fromArray(
[
'exception' => ($context['exception'] ?? null) instanceof \Throwable ? $context['exception'] : null,
'mechanism' => ($context['mechanism'] ?? null) instanceof ExceptionMechanism ? $context['mechanism'] : null,
'stacktrace' => ($context['stacktrace'] ?? null) instanceof Stacktrace ? $context['stacktrace'] : null,
'extra' => array_filter(
$context,
fn ($key) => !in_array($key, ['exception', 'mechanism', 'stacktrace']),
ARRAY_FILTER_USE_KEY
) ?: [],
]
);
}

/**
* Check if we can retrieve customer data.
*
Expand Down
49 changes: 12 additions & 37 deletions Plugin/MonologPlugin.php
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,31 @@

namespace JustBetter\Sentry\Plugin;

use JustBetter\Sentry\Helper\Data;
use JustBetter\Sentry\Model\SentryLog;
use Magento\Framework\App\DeploymentConfig;
use JustBetter\Sentry\Logger\Handler\Sentry;
use Magento\Framework\Logger\Monolog;
use Monolog\DateTimeImmutable;
use Monolog\LogRecord;
use Monolog\Processor\ProcessorInterface;

class MonologPlugin extends Monolog
{
/**
* @psalm-param array<callable(array): array> $processors
*
* @param string $name The logging channel, a simple descriptive name that is attached to all log records
* @param Data $sentryHelper
* @param SentryLog $sentryLog
* @param DeploymentConfig $deploymentConfig
* @param \Monolog\Handler\HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
* @param callable[] $processors Optional array of processors
* @param string $name The logging channel, a simple descriptive name that is attached to all log records
* @param Sentry $sentryHandler
* @param \Monolog\Handler\HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
* @param callable[] $processors Optional array of processors
*
* @phpstan-param array<(callable(LogRecord|array): LogRecord|array)|ProcessorInterface> $processors
*/
public function __construct(
$name,
protected Data $sentryHelper,
protected SentryLog $sentryLog,
protected DeploymentConfig $deploymentConfig,
Sentry $sentryHandler,
array $handlers = [],
array $processors = []
) {
parent::__construct($name, $handlers, $processors);
}
$handlers['sentry'] = $sentryHandler;

/**
* Adds a log record to Sentry.
*
* @param int $level The logging level
* @param string $message The log message
* @param array $context The log context
* @param DateTimeImmutable $datetime Datetime of log
*
* @return bool Whether the record has been processed
*/
public function addRecord(
int $level,
string $message,
array $context = [],
DateTimeImmutable $datetime = null
): bool {
if ($this->deploymentConfig->isAvailable() && $this->sentryHelper->isActive()) {
$this->sentryLog->send($message, $level, $context);
}

// @phpstan-ignore argument.type
return parent::addRecord($level, $message, $context, $datetime);
parent::__construct($name, $handlers, $processors);
}
}
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
"require": {
"php": ">=8.0",
"sentry/sdk": "^4.0",
"monolog/monolog": ">=2.7.0",
"monolog/monolog": ">=2.7.0|^3.0",
"magento/framework": "*",
"magento/module-csp": "*",
"nyholm/psr7": "^1.2",
"magento/module-config": "^101.2"
},
Expand Down Expand Up @@ -51,7 +52,7 @@
},
"scripts": {
"analyse": "vendor/bin/phpstan analyse --memory-limit='1G'",
"phpcs": "vendor/bin/phpcs --colors --standard=vendor/magento/magento-coding-standard/Magento2 --exclude=Generic.Files.LineLength --report=full,summary,gitblame --extensions=php,phtml --ignore=./vendor ./",
"phpcs": "vendor/bin/phpcs --colors --standard=vendor/magento/magento-coding-standard/Magento2 -s --exclude=Generic.Files.LineLength --report=full,summary,gitblame --extensions=php,phtml --ignore=./vendor ./",
"phpcbf": "vendor/bin/phpcbf --colors --standard=vendor/magento/magento-coding-standard/Magento2 --exclude=Generic.Files.LineLength --extensions=php,phtml --ignore=./vendor ./ || exit 0",
"codestyle": [
"@phpcbf",
Expand Down
23 changes: 0 additions & 23 deletions etc/di.xml
Original file line number Diff line number Diff line change
@@ -1,28 +1,6 @@
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="JustBetter\Sentry\Model\SentryLog">
<arguments>
<argument name="name" xsi:type="string">SentryLog</argument>
<argument name="handlers" xsi:type="array">
<item name="system" xsi:type="object">Magento\Framework\Logger\Handler\System</item>
</argument>
<argument name="processors" xsi:type="array"/>
<argument name="customerSession" xsi:type="object">Magento\Customer\Model\Session\Proxy</argument>
</arguments>
</type>

<type name="JustBetter\Sentry\Plugin\MonologPlugin">
<arguments>
<argument name="name" xsi:type="string"></argument>
<argument name="data" xsi:type="object">JustBetter\Sentry\Helper\Data\Proxy</argument>
<argument name="sentryLog" xsi:type="object">JustBetter\Sentry\Model\SentryLog\Proxy</argument>
<argument name="deploymentConfig" xsi:type="object">Magento\Framework\App\DeploymentConfig\Proxy</argument>
<argument name="handlers" xsi:type="array"></argument>
<argument name="processors" xsi:type="array"></argument>
</arguments>
</type>

<!-- Cannot use plugin https://github.com/magento/magento2/issues/14950 -->
<preference for="Magento\Framework\Logger\Monolog" type="JustBetter\Sentry\Plugin\MonologPlugin"/>
<type name="Magento\Framework\AppInterface">
Expand All @@ -42,5 +20,4 @@
</argument>
</arguments>
</type>

</config>
3 changes: 2 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ parameters:
excludePaths:
- vendor
- Test/*
level: 5
- Logger/Handler/Sentry.php
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're housing a version for V2 and V3 PHPStan will never be happy

level: 5