Skip to content
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

Added user context whenever possible #133

Merged
merged 12 commits into from
Nov 6, 2024
Merged
114 changes: 114 additions & 0 deletions Model/SentryInteraction.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,130 @@

// phpcs:disable Magento2.Functions.DiscouragedFunction

use Magento\Authorization\Model\UserContextInterface;
use Magento\Backend\Model\Auth\Session as AdminSession;
use Magento\Customer\Model\Session as CustomerSession;
use Magento\Framework\App\Area;
use Magento\Framework\App\State;
use Magento\Framework\Exception\LocalizedException;
use ReflectionClass;
use Sentry\State\Scope;

use function Sentry\captureException;
use function Sentry\configureScope;
use function Sentry\init;

class SentryInteraction
{
public function __construct(
private UserContextInterface $userContext,
private State $appState
) {
}

public function initialize($config)
{
init($config);
}

private function canGetUserData()
{
try {
return in_array(@$this->appState->getAreaCode(), [Area::AREA_ADMINHTML, Area::AREA_FRONTEND]);
} catch (LocalizedException $ex) {
return false;
}
}

private function getSessionUserData()
{
if (!$this->canGetUserData()) {
return [];
}

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$reflectionClass = new ReflectionClass($objectManager);
$sharedInstances = $reflectionClass->getProperty('_sharedInstances');
$sharedInstances->setAccessible(true);

if ($this->appState->getAreaCode() === Area::AREA_ADMINHTML) {
if (!array_key_exists(ltrim(AdminSession::class, '\\'), $sharedInstances->getValue($objectManager))) {
// Don't intitialise session if it has not already been started, this causes problems with dynamic resources.
return [];
}
$adminSession = $objectManager->get(AdminSession::class);

if ($adminSession->isLoggedIn()) {
return [
'id' => $adminSession->getUser()->getId(),
'email' => $adminSession->getUser()->getEmail(),
'user_type' => UserContextInterface::USER_TYPE_ADMIN,
];
}
}

if ($this->appState->getAreaCode() === Area::AREA_FRONTEND) {
if (!array_key_exists(ltrim(CustomerSession::class, '\\'), $sharedInstances->getValue($objectManager))) {
return [];
}
$customerSession = $objectManager->get(CustomerSession::class);

if ($customerSession->loggedIn()) {
return [
'id' => $customerSession->getCustomer()->getId(),
'email' => $customerSession->getCustomer()->getEmail(),
'website_id' => $customerSession->getCustomer()->getWebsiteId(),
'store_id' => $customerSession->getCustomer()->getStoreId(),
'user_type' => UserContextInterface::USER_TYPE_CUSTOMER,
];
}
}

return [];
}

public function addUserContext()
{
$userId = null;
$userType = null;
$userData = [];

\Magento\Framework\Profiler::start('SENTRY::add_user_context');

try {
$userId = $this->userContext->getUserId();
if ($userId) {
$userType = $this->userContext->getUserType();
}

if ($this->canGetUserData() && count($userData = $this->getSessionUserData())) {
$userId = $userData['id'] ?? $userId;
$userType = $userData['user_type'] ?? $userType;
unset($userData['user_type']);
}

if (!$userId) {
return;
}

configureScope(function (Scope $scope) use ($userType, $userId, $userData) {
$scope->setUser([
'id' => $userId,
...$userData,
'user_type' => match ($userType) {
UserContextInterface::USER_TYPE_INTEGRATION => 'integration',
UserContextInterface::USER_TYPE_ADMIN => 'admin',
UserContextInterface::USER_TYPE_CUSTOMER => 'customer',
UserContextInterface::USER_TYPE_GUEST => 'guest',
default => 'unknown'
},
]);
});
} catch (\Throwable $e) {
}
\Magento\Framework\Profiler::stop('SENTRY::add_user_context');
}

public function captureException(\Throwable $ex)
{
ob_start();
Expand Down
24 changes: 3 additions & 21 deletions Model/SentryLog.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function __construct(
protected Data $data,
protected Session $customerSession,
private State $appState,
private SentryInteraction $sentryInteraction,
array $handlers = [],
array $processors = []
) {
Expand Down Expand Up @@ -60,13 +61,14 @@ public function send($message, $logLevel, $context = [])
\Sentry\configureScope(
function (SentryScope $scope) use ($context, $customTags): void {
$this->setTags($scope, $customTags);
$this->setUser($scope);
if (false === empty($context)) {
$scope->setContext('Custom context', $context);
}
}
);

$this->sentryInteraction->addUserContext();

if ($message instanceof \Throwable) {
$lastEventId = \Sentry\captureException($message);
} else {
Expand All @@ -83,26 +85,6 @@ function (SentryScope $scope) use ($context, $customTags): void {
}
}

private function setUser(SentryScope $scope): void
{
try {
if (!$this->canGetCustomerData()
|| !$this->customerSession->isLoggedIn()) {
return;
}

$customerData = $this->customerSession->getCustomer();
$scope->setUser([
'id' => $customerData->getEntityId(),
'email' => $customerData->getEmail(),
'website_id' => $customerData->getWebsiteId(),
'store_id' => $customerData->getStoreId(),
]);
} catch (SessionException $e) {
return;
}
}

private function canGetCustomerData()
{
try {
Expand Down
1 change: 1 addition & 0 deletions Plugin/GlobalExceptionCatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public function aroundLaunch(AppInterface $subject, callable $proceed)
} catch (\Throwable $ex) {
try {
if ($this->sentryHelper->shouldCaptureException($ex)) {
$this->sentryInteraction->addUserContext();
$this->sentryInteraction->captureException($ex);
}
} catch (\Throwable $bigProblem) {
Expand Down
Loading