diff --git a/README.md b/README.md index a61492f..8a5212b 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,12 @@ return [ 'anonymous' => false, // Determines to log user info or not 'clientDsn' => getenv('SENTRY_DSN') ?: 'https://example@sentry.io/123456789', // Set as string or use environment variable. 'clientKey' => getenv('SENTRY_CLIENT_KEY') ?: 'z987654321a', // https://js.sentry-cdn.com/z987654321a.min.js + 'dataStorageLocation' => getenv('SENTRY_DATA_STORAGE_LOCATION') ?: 'US', // Can be either US or EU. Default is US if not specified 'excludedCodes' => ['400', '404', '429'], 'release' => getenv('SENTRY_RELEASE') ?: null, // Release number/name used by sentry. 'reportJsErrors' => false, 'sampleRate' => 1.0, + 'allowUrls' => [], // URL string or regex. JS errors that have been created on these will be sent to Sentry. 'ignoreErrors' => [ // Email link Microsoft Outlook crawler compatibility error // cf. https://forum.sentry.io/t/unhandledrejection-non-error-promise-rejection-captured-with-value/14062 diff --git a/src/Plugin.php b/src/Plugin.php index d3949b6..43c01ea 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -51,6 +51,12 @@ public function init() $info = $app->getInfo(); $settings = $this->getSettings(); + if(!$settings->validate()) { + Craft::error('Sentry settings are invalid: ' . json_encode($settings->getErrors()), $this->handle); + throw new Exception('Invalid Sentry plugin settings: '. json_encode($settings->getErrors())); + return; + } + if (!$this->isInstalled || !$settings->enabled) return; if (!$settings->clientDsn) { @@ -125,15 +131,31 @@ public function init() function (TemplateEvent $event) { $settings = $this->getSettings(); $view = Craft::$app->getView(); - $ignoreErrors = json_encode($settings->ignoreErrors); + + $regexMap = []; + + $allowUrls = array_map(function($url) use (&$regexMap) { + if (preg_match('/^\/(.+)\/([gimsuy]*)$/', $url, $m)) { + $key = '__REGEX_' . count($regexMap) . '__'; + $regexMap['"' . $key . '"'] = '/' . $m[1] . '/' . $m[2]; + return $key; + } + return $url; + }, $settings->allowUrls ?: []); + + $allowUrls = json_encode($allowUrls, JSON_UNESCAPED_SLASHES); + $allowUrls = str_replace(array_keys($regexMap), array_values($regexMap), $allowUrls); + + $dataStorageLocationSubdomain = $settings->dataStorageLocation == 'EU' ? 'js-de' : 'js'; $view->registerScript(" // Configure sentryOnLoad before adding the Loader Script window.sentryOnLoad = function () { Sentry.init({ - release: '$settings->release', - environment: '" . App::env('CRAFT_ENVIRONMENT') . "', - ignoreErrors: $ignoreErrors, + release: '$settings->release', + environment: '" . App::env('CRAFT_ENVIRONMENT') . "', + ignoreErrors: " . json_encode($settings->ignoreErrors) . ", + allowUrls: $allowUrls }); };", View::POS_END, $this->getScriptOptions()); @@ -141,7 +163,7 @@ function (TemplateEvent $event) { "", View::POS_END, array_merge([ - 'src' => "https://js.sentry-cdn.com/$settings->clientKey.min.js", + 'src' => "https://".$dataStorageLocationSubdomain.".sentry-cdn.com" ."/$settings->clientKey.min.js", 'crossorigin' => 'anonymous', ], $this->getScriptOptions()) ); diff --git a/src/models/Settings.php b/src/models/Settings.php index 11d44c5..3769e21 100644 --- a/src/models/Settings.php +++ b/src/models/Settings.php @@ -8,13 +8,15 @@ class Settings extends Model { public $enabled = true; public $anonymous = false; // Determines to log user info or not - public $clientDsn; - public $clientKey; + public string $clientDsn; + public string $clientKey; + public $dataStorageLocation = 'US'; public $excludedCodes = ['404']; - public $release; // Release number/name used by sentry. + public string $release; // Release number/name used by sentry. public $reportJsErrors = false; // Client only option public $sampleRate = 1.0; // Client only option public $ignoreErrors = []; + public $allowUrls = []; /** * @inheritdoc @@ -23,10 +25,11 @@ public function defineRules(): array { return [ [['enabled', 'anonymous', 'reportJsErrors'], 'boolean'], - [['clientDsn', 'clientKey', 'excludedCodes', 'release'], 'string'], - [['ignoreErrors'], 'array'], + [['clientDsn', 'clientKey', 'release', 'dataStorageLocation'], 'string'], + [['excludedCodes', 'ignoreErrors', 'allowUrls'], 'each', 'rule' => ['string']], [['clientDsn'], 'required'], [['sampleRate'], 'number', 'min' => 0, 'max' => 1], + [['dataStorageLocation'], 'in', 'range' => ['US', 'EU'], 'message' => 'Data Storage Location must be either "US" or "EU".'], ]; } }