diff --git a/README.md b/README.md index 61f88ea..7a34d3c 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,22 @@ sentry: # Trace 10% of requests traces_sample_rate: 0.1 -# Optional: Report scheduled tasks status to Sentry. See https://docs.sentry.io/product/crons/ for more information and check pricing before enabling this feature. frosh_sentry: + # Optional: Report scheduled tasks status to Sentry. See https://docs.sentry.io/product/crons/ for more information and check pricing before enabling this feature. report_scheduled_tasks: false + storefront: + # optional: if you want track errors occurs within the browser (javascript/cors/csp) + enabled: true + # optional: if you want record the user sessions. Please aware the GDPR. + replay_recording: + enabled: true + sample_rate: 0.1 + # optional: if you want measure the performance within the browser + tracing: + enabled: true + sample_rate: 0.1 + # you should always specify a sdk version. If you do not provide any version, a hard-coded version got used. We try to keep the version up to date with the latest version, but cause the fast release-line of the javascript SDK it is recommend to update the version number regularly. + javascript_sdk_version: "8.26.0" ``` ### Pictures diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 06de471..7a975c3 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -15,10 +15,29 @@ public function getConfigTreeBuilder(): TreeBuilder $treeBuilder = new TreeBuilder('frosh_sentry'); $rootNode = $treeBuilder->getRootNode(); - $rootNode + // @formatter:off + $rootNode // @phpstan-ignore-line ->children() ->booleanNode('report_scheduled_tasks')->defaultFalse()->end() + ->arrayNode('storefront') + ->children() + ->booleanNode('enabled')->defaultFalse()->end() + ->arrayNode('replay_recording') + ->children() + ->booleanNode('enabled')->defaultFalse()->end() + ->floatNode('sample_rate')->defaultValue(0.1)->end() + ->end() + ->end() + ->arrayNode('tracing') + ->children() + ->booleanNode('enabled')->defaultFalse()->end() + ->floatNode('sample_rate')->defaultValue(0.1)->end() + ->end() + ->end() + ->scalarNode('javascript_sdk_version')->defaultValue('8.26.0')->end() + ->end() ->end(); + // @formatter:on return $treeBuilder; } diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml new file mode 100644 index 0000000..a9cdc69 --- /dev/null +++ b/src/Resources/config/services.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/src/Resources/views/storefront/layout/meta.html.twig b/src/Resources/views/storefront/layout/meta.html.twig new file mode 100644 index 0000000..4411310 --- /dev/null +++ b/src/Resources/views/storefront/layout/meta.html.twig @@ -0,0 +1,7 @@ +{% sw_extends '@Storefront/storefront/layout/meta.html.twig' %} + +{% block layout_head_javascript_feature %} + {% sw_include '@ShopwareSentryBundle/storefront/sentry.html.twig' %} + + {{ parent() }} +{% endblock %} diff --git a/src/Resources/views/storefront/sentry.html.twig b/src/Resources/views/storefront/sentry.html.twig new file mode 100644 index 0000000..b54b8b8 --- /dev/null +++ b/src/Resources/views/storefront/sentry.html.twig @@ -0,0 +1,37 @@ +{% if sentry %} + {% block sentry %} + + + {% endblock %} +{% endif %} diff --git a/src/ShopwareSentryBundle.php b/src/ShopwareSentryBundle.php index f620b9b..0b26259 100644 --- a/src/ShopwareSentryBundle.php +++ b/src/ShopwareSentryBundle.php @@ -8,11 +8,11 @@ use Frosh\SentryBundle\Listener\FixRequestUrlListener; use Frosh\SentryBundle\Listener\SalesChannelContextListener; use Frosh\SentryBundle\Subscriber\ScheduledTaskSubscriber; +use Shopware\Core\Framework\Bundle; use Shopware\Core\System\SalesChannel\Event\SalesChannelContextCreatedEvent; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Event\RequestEvent; use Sentry\State\HubInterface; @@ -20,6 +20,8 @@ class ShopwareSentryBundle extends Bundle { public function build(ContainerBuilder $container): void { + parent::build($container); + $container ->register(SalesChannelContextListener::class) ->addTag('kernel.event_listener', ['event' => SalesChannelContextCreatedEvent::class, 'method' => '__invoke']) diff --git a/src/Subscriber/StorefrontPageSubscriber.php b/src/Subscriber/StorefrontPageSubscriber.php new file mode 100644 index 0000000..b07deae --- /dev/null +++ b/src/Subscriber/StorefrontPageSubscriber.php @@ -0,0 +1,73 @@ + 'onRender', + ]; + } + + public function onRender(StorefrontRenderEvent $event): void + { + if ($this->sentryOptions->getDsn() == null + || !$this->container->getParameter('frosh_sentry.storefront.enabled') + ) { + return; + } + + $jsSdkVersion = $this->container->getParameter('frosh_sentry.storefront.javascript_sdk_version'); + if (!is_string($jsSdkVersion)) { + return; + } + + $isReplayRecordingEnabled = $this->container->getParameter('frosh_sentry.storefront.replay_recording.enabled'); + $isPerformanceTracingEnabled = $this->container->getParameter('frosh_sentry.storefront.tracing.enabled'); + + if ($isReplayRecordingEnabled && $isPerformanceTracingEnabled) { + $jsFile = 'bundle.tracing.replay.min.js'; + } elseif ($isReplayRecordingEnabled && !$isPerformanceTracingEnabled) { + $jsFile = 'bundle.replay.min.js'; + } elseif (!$isReplayRecordingEnabled && $isPerformanceTracingEnabled) { + $jsFile = 'bundle.tracing.min.js'; + } elseif (!$isReplayRecordingEnabled && !$isPerformanceTracingEnabled) { + $jsFile = 'bundle.min.js'; + } else { + // this case should never happen + return; + } + + $replaySample = $this->container->getParameter('frosh_sentry.storefront.replay_recording.sample_rate'); + $tracingSample = $this->container->getParameter('frosh_sentry.storefront.tracing.sample_rate'); + + $event->setParameter('sentry', [ + 'dsn' => $this->sentryOptions->getDsn(), + 'javascript_src' => sprintf("https://browser.sentry-cdn.com/%s/%s", $jsSdkVersion, $jsFile), + 'replay_recording' => [ + 'enabled' => $isReplayRecordingEnabled, + 'sample_rate' => is_float($replaySample) ? $replaySample : 0.1, + ], + 'tracing' => [ + 'enabled' => $isPerformanceTracingEnabled, + 'sample_rate' => is_float($tracingSample) ? $tracingSample : 0.1, + ], + 'release' => $this->sentryOptions->getRelease(), + 'environment' => $this->sentryOptions->getEnvironment(), + ]); + } +}