Просмотр исходного кода

feat(onboarding): Add profiling to php platforms (#55843)

* Add the product selector and profiling docs to the platforms `php`,
`php-laravel` and `php-symfony2`.
* Reduce content to the information that is necessary to get started

Closes https://github.com/getsentry/sentry/issues/55605
Closes https://github.com/getsentry/sentry/issues/55606
Closes https://github.com/getsentry/sentry/issues/55607
ArthurKnaus 1 год назад
Родитель
Сommit
1f21a4c32c

+ 7 - 0
static/app/components/onboarding/productSelection.tsx

@@ -125,6 +125,13 @@ export const platformProductAvailability = {
     ProductSolution.PROFILING,
   ],
   'node-koa': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
+  php: [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
+  'php-laravel': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
+  // TODO(arthur): cleanup naming missmatch between php-symfony and php-symfony2
+  ['php-symfony' as 'php-symfony2']: [
+    ProductSolution.PERFORMANCE_MONITORING,
+    ProductSolution.PROFILING,
+  ],
   python: [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   'python-aiohttp': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   'python-awslambda': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],

+ 5 - 1
static/app/gettingStartedDocs/php/laravel.spec.tsx

@@ -9,7 +9,11 @@ describe('GettingStartedWithLaravel', function () {
     const {container} = render(<GettingStartedWithLaravel dsn="test-dsn" />);
 
     // Steps
-    for (const step of steps()) {
+    for (const step of steps({
+      dsn: 'test-dsn',
+      hasPerformance: true,
+      hasProfiling: true,
+    })) {
       expect(
         screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
       ).toBeInTheDocument();

+ 53 - 133
static/app/gettingStartedDocs/php/laravel.tsx

@@ -1,11 +1,16 @@
-import {Fragment} from 'react';
-
 import ExternalLink from 'sentry/components/links/externalLink';
 import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
 import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {ProductSolution} from 'sentry/components/onboarding/productSelection';
 import {t, tct} from 'sentry/locale';
 
+interface StepProps {
+  dsn: string;
+  hasPerformance: boolean;
+  hasProfiling: boolean;
+}
+
 // Configuration Start
 const introduction = (
   <p>
@@ -25,7 +30,9 @@ const introduction = (
 
 export const steps = ({
   dsn,
-}: Partial<Pick<ModuleProps, 'dsn'>> = {}): LayoutProps['steps'] => [
+  hasPerformance,
+  hasProfiling,
+}: StepProps): LayoutProps['steps'] => [
   {
     type: StepType.INSTALL,
     configurations: [
@@ -40,6 +47,15 @@ export const steps = ({
         language: 'bash',
         code: `composer require sentry/sentry-laravel`,
       },
+      ...(hasProfiling
+        ? [
+            {
+              description: t('Install the Excimer extension via PECL:'),
+              language: 'bash',
+              code: 'pecl install excimer',
+            },
+          ]
+        : []),
       {
         description: (
           <p>
@@ -63,20 +79,6 @@ public function register() {
         `,
       },
     ],
-    additionalInfo: (
-      <p>
-        {tct(
-          'Alternatively, you can configure Sentry in your [laravelLogChannelLink:Laravel Log Channel], allowing you to log [codeInfo:info] and [codeDebug:debug] as well.',
-          {
-            codeInfo: <code />,
-            codeDebug: <code />,
-            laravelLogChannelLink: (
-              <ExternalLink href="https://docs.sentry.io/platforms/php/guides/laravel/usage/#log-channels" />
-            ),
-          }
-        )}
-      </p>
-    ),
   },
   {
     type: StepType.CONFIGURE,
@@ -90,148 +92,66 @@ public function register() {
         description: (
           <p>
             {tct(
-              'It creates the config file ([sentryPHPCode:config/sentry.php]) and adds the [dsnCode:DSN] to your ".env" file.',
-              {dsnCode: <code />, sentryPHPCode: <code />}
+              'It creates the config file ([sentryPHPCode:config/sentry.php]) and adds the [dsnCode:DSN] to your [envCode:.env] file where you can add further configuration options:',
+              {sentryPHPCode: <code />, dsnCode: <code />, envCode: <code />}
             )}
           </p>
         ),
         language: 'shell',
-        code: `SENTRY_LARAVEL_DSN=${dsn}`,
+        code: `SENTRY_LARAVEL_DSN=${dsn}${
+          hasPerformance
+            ? `
+# Specify a fixed sample rate
+SENTRY_TRACES_SAMPLE_RATE=1.0`
+            : ''
+        }${
+          hasProfiling
+            ? `
+# Set a sampling rate for profiling - this is relative to traces_sample_rate
+SENTRY_PROFILES_SAMPLE_RATE=1.0`
+            : ''
+        }`,
       },
     ],
   },
   {
     type: StepType.VERIFY,
-    configurations: [
-      {
-        description: <h5>{t('Verify With Artisan')}</h5>,
-        configurations: [
-          {
-            description: (
-              <p>
-                {tct(
-                  'You can test your configuration using the provided [code:sentry:test] artisan command:',
-                  {
-                    code: <code />,
-                  }
-                )}
-              </p>
-            ),
-            language: 'shell',
-            code: 'php artisan sentry:test',
-          },
-        ],
-      },
-      {
-        description: <h5>{t('Verify With Code')}</h5>,
-        configurations: [
-          {
-            description: t(
-              'You can verify that Sentry is capturing errors in your Laravel application by creating a route that will throw an exception:'
-            ),
-            language: 'php',
-            code: `
-Route::get('/debug-sentry', function () {
-    throw new Exception('My first Sentry error!');
-});
-            `,
-            additionalInfo: t(
-              'Visiting this route will trigger an exception that will be captured by Sentry.'
-            ),
-          },
-        ],
-      },
-    ],
-  },
-  {
-    title: t('Performance Monitoring'),
     configurations: [
       {
         description: (
           <p>
             {tct(
-              'Set [tracesSampleRateCode:traces_sample_rate] in [sentryPhpCode:config/sentry.php] or [sentryTracesSampleRateCode:SENTRY_TRACES_SAMPLE_RATE] in your ".env" to a value greater than "0.0". Setting a value greater than "0.0" will enable Performance Monitoring, "0" (the default) will disable Performance Monitoring.',
+              'You can test your configuration using the provided [code:sentry:test] artisan command:',
               {
-                tracesSampleRateCode: <code />,
-                sentryPhpCode: <code />,
-                sentryTracesSampleRateCode: <code />,
+                code: <code />,
               }
             )}
           </p>
         ),
         language: 'shell',
-        code: `
-# Be sure to lower this value in production otherwise you could burn through your quota quickly.
-SENTRY_TRACES_SAMPLE_RATE=1.0
-        `,
-        additionalInfo: (
-          <Fragment>
-            {t(
-              'The example configuration above will transmit 100% of captured traces. Be sure to lower this value in production or you could use up your quota quickly.'
-            )}
-            <p>
-              {tct(
-                'You can also be more granular with the sample rate by using the traces_sampler option. Learn more in [usingSampleToFilterLink:Using Sampling to Filter Transaction Events].',
-                {
-                  usingSampleToFilterLink: (
-                    <ExternalLink href="https://docs.sentry.io/platforms/php/guides/laravel/configuration/filtering/#using-sampling-to-filter-transaction-events" />
-                  ),
-                }
-              )}
-            </p>
-            <p>
-              {tct(
-                "Performance data is transmitted using a new event type called 'transactions', which you can learn about in Distributed Tracing.",
-                {
-                  distributedTracingLink: (
-                    <ExternalLink href="https://docs.sentry.io/product/sentry-basics/tracing/distributed-tracing/#traces-transactions-and-spans" />
-                  ),
-                }
-              )}
-            </p>
-          </Fragment>
-        ),
+        code: 'php artisan sentry:test',
       },
     ],
   },
-  {
-    title: t('Local Development and Testing'),
-    description: (
-      <Fragment>
-        {t(
-          'When Sentry is installed in your application, it will also be active when you are developing or running tests.'
-        )}
-        <p>
-          {tct(
-            "You most likely don't want errors to be sent to Sentry when you are developing or running tests. To avoid this, set the DSN value to [code:null] to disable sending errors to Sentry.",
-            {
-              code: <code />,
-            }
-          )}
-        </p>
-        <p>
-          {tct(
-            'You can also do this by not defining [sentryLaravelDsnCode:SENTRY_LARAVEL_DSN] in your [envCode:.env] or by defining it as [sentryLaravelDsnNullCode:SENTRY_LARAVEL_DSN=null].',
-            {
-              sentryLaravelDsnNullCode: <code />,
-              envCode: <code />,
-              sentryLaravelDsnCode: <code />,
-            }
-          )}
-        </p>
-        <p>
-          {t(
-            "If you do leave Sentry enabled when developing or running tests, it's possible for it to have a negative effect on the performance of your application or test suite."
-          )}
-        </p>
-      </Fragment>
-    ),
-  },
 ];
 // Configuration End
 
-export function GettingStartedWithLaravel({dsn, ...props}: ModuleProps) {
-  return <Layout steps={steps({dsn})} introduction={introduction} {...props} />;
+export function GettingStartedWithLaravel({
+  dsn,
+  activeProductSelection = [],
+  ...props
+}: ModuleProps) {
+  const hasPerformance = activeProductSelection.includes(
+    ProductSolution.PERFORMANCE_MONITORING
+  );
+  const hasProfiling = activeProductSelection.includes(ProductSolution.PROFILING);
+  return (
+    <Layout
+      introduction={introduction}
+      steps={steps({dsn, hasPerformance, hasProfiling})}
+      {...props}
+    />
+  );
 }
 
 export default GettingStartedWithLaravel;

+ 5 - 1
static/app/gettingStartedDocs/php/php.spec.tsx

@@ -9,7 +9,11 @@ describe('GettingStartedWithPHP', function () {
     const {container} = render(<GettingStartedWithPHP dsn="test-dsn" />);
 
     // Steps
-    for (const step of steps()) {
+    for (const step of steps({
+      dsn: 'test-dsn',
+      hasPerformance: true,
+      hasProfiling: true,
+    })) {
       expect(
         screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
       ).toBeInTheDocument();

+ 69 - 22
static/app/gettingStartedDocs/php/php.tsx

@@ -2,31 +2,49 @@ import ExternalLink from 'sentry/components/links/externalLink';
 import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
 import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {ProductSolution} from 'sentry/components/onboarding/productSelection';
 import {t, tct} from 'sentry/locale';
 
+interface StepProps {
+  dsn: string;
+  hasPerformance: boolean;
+  hasProfiling: boolean;
+}
+
 // Configuration Start
 export const steps = ({
   dsn,
-}: Partial<Pick<ModuleProps, 'dsn'>> = {}): LayoutProps['steps'] => [
+  hasPerformance,
+  hasProfiling,
+}: StepProps): LayoutProps['steps'] => [
   {
     type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct(
-          'To install the PHP SDK, you need to be using Composer in your project. For more details about Composer, see the [composerDocumentationLink:Composer documentation].',
-          {
-            composerDocumentationLink: (
-              <ExternalLink href="https://getcomposer.org/doc/" />
-            ),
-          }
-        )}
-      </p>
-    ),
     configurations: [
       {
+        description: (
+          <p>
+            {tct(
+              'To install the PHP SDK, you need to be using Composer in your project. For more details about Composer, see the [composerDocumentationLink:Composer documentation].',
+              {
+                composerDocumentationLink: (
+                  <ExternalLink href="https://getcomposer.org/doc/" />
+                ),
+              }
+            )}
+          </p>
+        ),
         language: 'bash',
         code: 'composer require sentry/sdk',
       },
+      ...(hasProfiling
+        ? [
+            {
+              description: t('Install the Excimer extension via PECL:'),
+              language: 'bash',
+              code: 'pecl install excimer',
+            },
+          ]
+        : []),
     ],
   },
   {
@@ -37,7 +55,33 @@ export const steps = ({
     configurations: [
       {
         language: 'php',
-        code: `\\Sentry\\init(['dsn' => '${dsn}' ]);`,
+        code: `\\Sentry\\init([
+    'dsn' => '${dsn}',${
+          hasPerformance
+            ? `
+    // Specify a fixed sample rate
+    'traces_sample_rate' => 1.0,`
+            : ''
+        }${
+          hasProfiling
+            ? `
+    // Set a sampling rate for profiling - this is relative to traces_sample_rate
+    'profiles_sample_rate' => 1.0,`
+            : ''
+        }
+]);`,
+        additionalInfo: hasPerformance && (
+          <p>
+            {tct(
+              'To instrument certain regions of your code, you can [instrumentationLink:create transactions to capture them].',
+              {
+                instrumentationLink: (
+                  <ExternalLink href="https://docs.sentry.io/platforms/php/performance/instrumentation/custom-instrumentation/" />
+                ),
+              }
+            )}
+          </p>
+        ),
       },
     ],
   },
@@ -54,20 +98,23 @@ try {
   $this->functionFailsForSure();
 } catch (\\Throwable $exception) {
   \\Sentry\\captureException($exception);
-}
-
-// OR
-
-\\Sentry\\captureLastError();
-        `,
+}`,
       },
     ],
   },
 ];
 // Configuration End
 
-export function GettingStartedWithPHP({dsn, ...props}: ModuleProps) {
-  return <Layout steps={steps({dsn})} {...props} />;
+export function GettingStartedWithPHP({
+  dsn,
+  activeProductSelection = [],
+  ...props
+}: ModuleProps) {
+  const hasPerformance = activeProductSelection.includes(
+    ProductSolution.PERFORMANCE_MONITORING
+  );
+  const hasProfiling = activeProductSelection.includes(ProductSolution.PROFILING);
+  return <Layout steps={steps({dsn, hasPerformance, hasProfiling})} {...props} />;
 }
 
 export default GettingStartedWithPHP;

+ 5 - 1
static/app/gettingStartedDocs/php/symfony.spec.tsx

@@ -9,7 +9,11 @@ describe('GettingStartedWithSymfony', function () {
     const {container} = render(<GettingStartedWithSymfony dsn="test-dsn" />);
 
     // Steps
-    for (const step of steps()) {
+    for (const step of steps({
+      dsn: 'test-dsn',
+      hasPerformance: true,
+      hasProfiling: true,
+    })) {
       expect(
         screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
       ).toBeInTheDocument();

+ 66 - 161
static/app/gettingStartedDocs/php/symfony.tsx

@@ -1,11 +1,16 @@
-import {Fragment} from 'react';
-
 import ExternalLink from 'sentry/components/links/externalLink';
 import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
 import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {ProductSolution} from 'sentry/components/onboarding/productSelection';
 import {t, tct} from 'sentry/locale';
 
+interface StepProps {
+  dsn: string;
+  hasPerformance: boolean;
+  hasProfiling: boolean;
+}
+
 // Configuration Start
 const introduction = (
   <p>
@@ -18,7 +23,9 @@ const introduction = (
 
 export const steps = ({
   dsn,
-}: Partial<Pick<ModuleProps, 'dsn'>> = {}): LayoutProps['steps'] => [
+  hasPerformance,
+  hasProfiling,
+}: StepProps): LayoutProps['steps'] => [
   {
     type: StepType.INSTALL,
     configurations: [
@@ -31,37 +38,15 @@ export const steps = ({
         ),
         code: 'composer require sentry/sentry-symfony',
       },
-      {
-        language: 'yaml',
-        description: (
-          <p>
-            {tct(
-              'Due to a bug in all versions below "6.0" of the [sensioFrameworkExtraBundleCode:SensioFrameworkExtraBundle] bundle, you will likely receive an error during the execution of the command above related to the missing [nyholmPsr7FactoryPsr17FactoryCode:NyholmPsr7FactoryPsr17Factory] class. To workaround the issue, if you are not using the PSR-7 bridge, please change the configuration of that bundle as follows:',
-              {
-                sensioFrameworkExtraBundleCode: <code />,
-                nyholmPsr7FactoryPsr17FactoryCode: <code />,
-              }
-            )}
-          </p>
-        ),
-        code: `
-sensio_framework_extra:
-  psr_message:
-  enabled: false
-        `,
-        additionalInfo: (
-          <p>
-            {tct(
-              'For more details about the issue see [link:https://github.com/sensiolabs/SensioFrameworkExtraBundle/pull/710].',
-              {
-                link: (
-                  <ExternalLink href="https://github.com/sensiolabs/SensioFrameworkExtraBundle/pull/710" />
-                ),
-              }
-            )}
-          </p>
-        ),
-      },
+      ...(hasProfiling
+        ? [
+            {
+              description: t('Install the Excimer extension via PECL:'),
+              language: 'bash',
+              code: 'pecl install excimer',
+            },
+          ]
+        : []),
     ],
   },
   {
@@ -71,13 +56,43 @@ sensio_framework_extra:
         description: (
           <p>{tct('Add your DSN to your [code:.env] file:', {code: <code />})}</p>
         ),
-        language: 'plain',
+        language: 'shell',
         code: `
 ###> sentry/sentry-symfony ###
 SENTRY_DSN="${dsn}"
 ###< sentry/sentry-symfony ###
         `,
       },
+      ...(hasPerformance || hasProfiling
+        ? [
+            {
+              description: (
+                <p>
+                  {tct(
+                    'Add further configuration options to your [code:config/packages/sentry.yaml] file:',
+                    {code: <code />}
+                  )}
+                </p>
+              ),
+              language: 'yaml',
+              code: `when@prod:
+    sentry:
+        dsn: '%env(SENTRY_DSN)%'${
+          hasPerformance
+            ? `
+        # Specify a fixed sample rate
+        traces_sample_rate: 1.0`
+            : ''
+        }${
+                hasProfiling
+                  ? `
+        # Set a sampling rate for profiling - this is relative to traces_sample_rate
+        profiles_sample_rate: 1.0`
+                  : ''
+              }`,
+            },
+          ]
+        : []),
     ],
   },
   {
@@ -139,135 +154,25 @@ class SentryTestController extends AbstractController {
       </p>
     ),
   },
-  {
-    title: t('Performance monitoring'),
-    description: (
-      <Fragment>
-        {t('Performance monitoring integrations to support tracing')}
-        <p>
-          {t(
-            'The process of logging the events that took place during a request, often across multiple services are enabled by default. To use them, update to the latest version of the SDK.'
-          )}
-        </p>
-        <p>
-          {tct(
-            'These integrations hook into critical paths of the framework and of the vendors. As a result, there may be a performance penalty. To disable tracing, please see the [integrationDocumentationLink:Integrations documentation].',
-            {
-              integrationDocumentationLink: (
-                <ExternalLink href="https://docs.sentry.io/platforms/php/guides/symfony/performance/instrumentation/automatic-instrumentation/" />
-              ),
-            }
-          )}
-        </p>
-      </Fragment>
-    ),
-    configurations: [
-      {
-        description: (
-          <p>
-            {tct(
-              "If you [strong:are not] using Symfony Flex, you'll also need to enable the bundle in [code:config/bundles.php]:",
-              {
-                code: <code />,
-                strong: <strong />,
-              }
-            )}
-          </p>
-        ),
-        language: 'php',
-        code: `
-<?php
-
-  return [
-    // ...
-    Sentry\\SentryBundle\\SentryBundle::class => ['all' => true],
-  ];
-        `,
-      },
-    ],
-  },
-  {
-    title: t('Monolog Integration'),
-    configurations: [
-      {
-        description: (
-          <p>
-            {tct(
-              'If you are using [monologLink:Monolog] to report events instead of the typical error listener approach, you need this additional configuration to log the errors correctly:',
-              {
-                monologLink: <ExternalLink href="https://github.com/Seldaek/monolog" />,
-              }
-            )}
-          </p>
-        ),
-        language: 'yaml',
-        code: `
-sentry:
-  register_error_listener: false # Disables the ErrorListener to avoid duplicated log in sentry
-  register_error_handler: false # Disables the ErrorListener, ExceptionListener and FatalErrorListener integrations of the base PHP SDK
-
-monolog:
-  handlers:
-    sentry:
-      type: sentry
-      level: !php/const Monolog\\Logger::ERROR
-      hub_id: Sentry\\State\\HubInterface
-        `,
-      },
-      {
-        description: (
-          <p>
-            {tct(
-              'f you are using a version of [monologBundleLink:MonologBundle] prior to [code:3.7], you need to configure the handler as a service instead:',
-              {
-                monologBundleLink: (
-                  <ExternalLink href="https://github.com/symfony/monolog-bundle" />
-                ),
-                code: <code />,
-              }
-            )}
-          </p>
-        ),
-        language: 'yaml',
-        code: `
-monolog:
-  handlers:
-    sentry:
-      type: service
-      id: Sentry\\Monolog\\Handler
-
-services:
-  Sentry\\Monolog\\Handler:
-    arguments:
-      $hub: '@Sentry\\State\\HubInterface'
-      $level: !php/const Monolog\\Logger::ERROR
-        `,
-      },
-      {
-        description: (
-          <p>
-            {tct(
-              'Additionally, you can register the [code:PsrLogMessageProcessor] to resolve PSR-3 placeholders in reported messages:',
-              {
-                code: <code />,
-              }
-            )}
-          </p>
-        ),
-        language: 'yaml',
-        code: `
-services:
-  Monolog\\Processor\\PsrLogMessageProcessor:
-    tags: { name: monolog.processor, handler: sentry }
-        `,
-      },
-    ],
-  },
 ];
 // Configuration End
 
-export function GettingStartedWithSymfony({dsn, ...props}: ModuleProps) {
-  return <Layout steps={steps({dsn})} introduction={introduction} {...props} />;
+export function GettingStartedWithSymfony({
+  dsn,
+  activeProductSelection = [],
+  ...props
+}: ModuleProps) {
+  const hasPerformance = activeProductSelection.includes(
+    ProductSolution.PERFORMANCE_MONITORING
+  );
+  const hasProfiling = activeProductSelection.includes(ProductSolution.PROFILING);
+  return (
+    <Layout
+      introduction={introduction}
+      steps={steps({dsn, hasPerformance, hasProfiling})}
+      {...props}
+    />
+  );
 }
 
 export default GettingStartedWithSymfony;