import ExternalLink from 'sentry/components/links/externalLink';
import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
import type {
Docs,
DocsParams,
OnboardingConfig,
} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {
getCrashReportModalConfigDescription,
getCrashReportModalIntroduction,
getCrashReportSDKInstallFirstStep,
} from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding';
import replayOnboardingJsLoader from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader';
import {t, tct} from 'sentry/locale';
type Params = DocsParams;
const getExceptionHandlerSnippet = () => `
withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
Integration::handles($exceptions);
})->create();`;
const getConfigureSnippet = (params: Params) =>
`SENTRY_LARAVEL_DSN=${params.dsn}${
params.isPerformanceSelected
? `
# Specify a fixed sample rate
SENTRY_TRACES_SAMPLE_RATE=1.0`
: ''
}${
params.isProfilingSelected
? `
# Set a sampling rate for profiling - this is relative to traces_sample_rate
SENTRY_PROFILES_SAMPLE_RATE=1.0`
: ''
}`;
const getMetricsInstallSnippet = () => `
composer install sentry/sentry-laravel
composer update sentry/sentry-laravel -W`;
const getMetricsVerifySnippet = () => `
use function \\Sentry\\metrics;
// Add 4 to a counter named 'hits'
metrics()->increment('hits', 4);
metrics()->flush();
// We recommend registering the flush call in a shutdown function
register_shutdown_function(static fn () => metrics()->flush());
// Or call flush in a Terminable Middleware
use Closure;
use Illuminate\\Http\\Request;
use Symfony\\Component\\HttpFoundation\\Response;
use function \\Sentry\\metrics;
class SentryMetricsMiddleware
{
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
public function terminate(Request $request, Response $response): void
{
metrics()->flush();
}
}`;
const onboarding: OnboardingConfig = {
introduction: () =>
tct(
'This guide is for Laravel 11.0 an up. We also provide instructions for [otherVersionsLink:other versions] as well as [lumenSpecificLink:Lumen-specific instructions].',
{
otherVersionsLink: (
,
}),
language: 'bash',
code: `composer require sentry/sentry-laravel`,
},
...(params.isProfilingSelected
? [
{
description: t('Install the Excimer extension via PECL:'),
language: 'bash',
code: 'pecl install excimer',
},
{
description: tct(
"The Excimer PHP extension supports PHP 7.2 and up. Excimer requires Linux or macOS and doesn't support Windows. For additional ways to install Excimer, see [sentryPhpDocumentationLink: Sentry documentation].",
{
sentryPhpDocumentationLink: (
,
}
),
language: 'php',
code: getExceptionHandlerSnippet(),
},
],
},
],
configure: (params: Params) => [
{
type: StepType.CONFIGURE,
configurations: [
{
description: t('Configure the Sentry DSN with this command:'),
language: 'shell',
code: `php artisan sentry:publish --dsn=${params.dsn}`,
},
{
description: tct(
'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:
, dsnCode:
, envCode:
}
),
language: 'shell',
code: getConfigureSnippet(params),
},
],
},
],
verify: () => [
{
type: StepType.VERIFY,
configurations: [
{
description: tct(
'You can test your configuration using the provided [code:sentry:test] artisan command:',
{
code:
,
}
),
language: 'shell',
code: 'php artisan sentry:test',
},
],
},
],
nextSteps: () => [],
};
const customMetricsOnboarding: OnboardingConfig = {
install: () => [
{
type: StepType.INSTALL,
description: tct(
'You need a minimum version [codeVersionLaravel:4.0.0] of the Laravel SDK and a minimum version [codeVersion:4.3.0] of the PHP SDK installed',
{
codeVersionLaravel:
,
codeVersion:
,
}
),
configurations: [
{
language: 'bash',
code: getMetricsInstallSnippet(),
},
],
},
],
configure: () => [
{
type: StepType.CONFIGURE,
description: tct(
'Once the SDK is installed or updated, you can enable code locations being emitted with your metrics in your [code:config/sentry.php] file:',
{
code:
,
}
),
configurations: [
{
code: [
{
label: 'PHP',
value: 'php',
language: 'php',
code: `'attach_metric_code_locations' => true,`,
},
],
},
],
},
],
verify: () => [
{
type: StepType.VERIFY,
description: tct(
"Then you'll be able to add metrics as [codeCounters:counters], [codeSets:sets], [codeDistribution:distributions], and [codeGauge:gauges]. Try out this example:",
{
codeCounters:
,
codeSets:
,
codeDistribution:
,
codeGauge:
,
codeNamespace:
,
}
),
configurations: [
{
code: [
{
label: 'PHP',
value: 'php',
language: 'php',
code: getMetricsVerifySnippet(),
},
],
},
{
description: t(
'With a bit of delay you can see the data appear in the Sentry UI.'
),
},
{
description: tct(
'Learn more about metrics and how to configure them, by reading the [docsLink:docs].',
{
docsLink: (
}
),
code: [
{
label: 'HTML',
value: 'html',
language: 'html',
code: `
}
),
code: [
{
label: 'PHP',
value: 'php',
language: 'php',
code: `bound('sentry') && $this->shouldReport($exception)) {
app('sentry')->captureException($exception);
}
parent::report($exception);
}
// This method is ONLY needed for Laravel 5 up to 5.4.
// You can skip this method if you are using Laravel 5.5+.
public function render($request, Exception $exception)
{
// Convert all non-http exceptions to a proper 500 http exception
// if we don't do this exceptions are shown as a default template
// instead of our own view in resources/views/errors/500.blade.php
if ($this->shouldReport($exception) && !$this->isHttpException($exception) && !config('app.debug')) {
$exception = new HttpException(500, 'Whoops!');
}
return parent::render($request, $exception);
}
}`,
},
],
},
],
},
],
configure: () => [
{
type: StepType.CONFIGURE,
description: getCrashReportModalConfigDescription({
link: 'https://docs.sentry.io/platforms/php/guides/laravel/user-feedback/configuration/#crash-report-modal',
}),
},
],
verify: () => [],
nextSteps: () => [],
};
const docs: Docs = {
onboarding,
replayOnboardingJsLoader,
customMetricsOnboarding,
crashReportOnboarding,
};
export default docs;