Skip to content

Commit bf155b8

Browse files
Add Laravel about command registration (#768)
Co-authored-by: Alex Bouma <alex@bouma.me>
1 parent ba87236 commit bf155b8

File tree

3 files changed

+158
-0
lines changed

3 files changed

+158
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace Sentry\Laravel\Console;
4+
5+
use Sentry\Client;
6+
use Sentry\Laravel\Version;
7+
use Sentry\State\HubInterface;
8+
9+
class AboutCommandIntegration
10+
{
11+
public function __invoke(HubInterface $hub): array
12+
{
13+
$client = $hub->getClient();
14+
15+
if ($client === null) {
16+
return [
17+
'Enabled' => '<fg=red;options=bold>NOT CONFIGURED</>',
18+
'Laravel SDK Version' => Version::SDK_VERSION,
19+
'PHP SDK Version' => Client::SDK_VERSION,
20+
];
21+
}
22+
23+
$options = $client->getOptions();
24+
25+
// Note: order is not important since Laravel orders these alphabetically
26+
return [
27+
'Enabled' => $options->getDsn() ? '<fg=green;options=bold>YES</>' : '<fg=red;options=bold>MISSING DSN</>',
28+
'Environment' => $options->getEnvironment() ?: '<fg=yellow;options=bold>NOT SET</>',
29+
'Laravel SDK Version' => Version::SDK_VERSION,
30+
'PHP SDK Version' => Client::SDK_VERSION,
31+
'Release' => $options->getRelease() ?: '<fg=yellow;options=bold>NOT SET</>',
32+
'Sample Rate Errors' => $this->formatSampleRate($options->getSampleRate()),
33+
'Sample Rate Performance Monitoring' => $this->formatSampleRate($options->getTracesSampleRate(), $options->getTracesSampler() !== null),
34+
'Sample Rate Profiling' => $this->formatSampleRate($options->getProfilesSampleRate()),
35+
'Send Default PII' => $options->shouldSendDefaultPii() ? '<fg=green;options=bold>ENABLED</>' : '<fg=yellow;options=bold>DISABLED</>',
36+
];
37+
}
38+
39+
private function formatSampleRate(?float $sampleRate, bool $hasSamplerCallback = false): string
40+
{
41+
if ($hasSamplerCallback) {
42+
return '<fg=green;options=bold>CUSTOM SAMPLER</>';
43+
}
44+
45+
if ($sampleRate === null) {
46+
return '<fg=yellow;options=bold>NOT SET</>';
47+
}
48+
49+
return number_format($sampleRate * 100) . '%';
50+
}
51+
}

src/Sentry/Laravel/ServiceProvider.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@
66
use Illuminate\Contracts\Events\Dispatcher;
77
use Illuminate\Contracts\Http\Kernel as HttpKernelInterface;
88
use Illuminate\Foundation\Application as Laravel;
9+
use Illuminate\Foundation\Console\AboutCommand;
910
use Illuminate\Foundation\Http\Kernel as HttpKernel;
1011
use Illuminate\Http\Request;
1112
use Illuminate\Log\LogManager;
13+
use Illuminate\Support\Facades\Config;
1214
use Laravel\Lumen\Application as Lumen;
1315
use RuntimeException;
16+
use Sentry\Client;
1417
use Sentry\ClientBuilder;
1518
use Sentry\ClientBuilderInterface;
1619
use Sentry\Event;
1720
use Sentry\EventHint;
1821
use Sentry\Integration as SdkIntegration;
22+
use Sentry\Laravel\Console\AboutCommandIntegration;
1923
use Sentry\Laravel\Console\PublishCommand;
2024
use Sentry\Laravel\Console\TestCommand;
2125
use Sentry\Laravel\Features\Feature;
@@ -91,6 +95,8 @@ public function boot(): void
9195
}
9296

9397
$this->registerArtisanCommands();
98+
99+
$this->registerAboutCommandIntegration();
94100
}
95101
}
96102

@@ -201,6 +207,19 @@ protected function registerArtisanCommands(): void
201207
]);
202208
}
203209

210+
/**
211+
* Register the `php artisan about` command integration.
212+
*/
213+
protected function registerAboutCommandIntegration(): void
214+
{
215+
// The about command is only available in Laravel 9 and up so we need to check if it's available to us
216+
if (!class_exists(AboutCommand::class)) {
217+
return;
218+
}
219+
220+
AboutCommand::add('Sentry', AboutCommandIntegration::class);
221+
}
222+
204223
/**
205224
* Configure and register the Sentry client with the container.
206225
*/
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
namespace Sentry\Console;
4+
5+
use Illuminate\Foundation\Console\AboutCommand;
6+
use Illuminate\Support\Facades\Artisan;
7+
use Sentry\Client;
8+
use Sentry\Laravel\Tests\TestCase;
9+
use Sentry\Laravel\Version;
10+
use Sentry\State\Hub;
11+
use Sentry\State\HubInterface;
12+
13+
class AboutCommandIntegrationTest extends TestCase
14+
{
15+
protected function setUp(): void
16+
{
17+
if (!class_exists(AboutCommand::class)) {
18+
$this->markTestSkipped('The about command is only available in Laravel 9.0+');
19+
}
20+
21+
parent::setUp();
22+
}
23+
24+
public function testAboutCommandContainsExpectedData(): void
25+
{
26+
$this->resetApplicationWithConfig([
27+
'sentry.release' => '1.2.3',
28+
'sentry.environment' => 'testing',
29+
'sentry.traces_sample_rate' => 0.95,
30+
]);
31+
32+
$expectedData = [
33+
'environment' => 'testing',
34+
'release' => '1.2.3',
35+
'sample_rate_errors' => '100%',
36+
'sample_rate_profiling' => 'NOT SET',
37+
'sample_rate_performance_monitoring' => '95%',
38+
'send_default_pii' => 'DISABLED',
39+
'php_sdk_version' => Client::SDK_VERSION,
40+
'laravel_sdk_version' => Version::SDK_VERSION,
41+
];
42+
43+
$actualData = $this->runArtisanAboutAndReturnSentryData();
44+
45+
foreach ($expectedData as $key => $value) {
46+
$this->assertArrayHasKey($key, $actualData);
47+
$this->assertEquals($value, $actualData[$key]);
48+
}
49+
}
50+
51+
public function testAboutCommandContainsExpectedDataWithoutHubClient(): void
52+
{
53+
$this->app->bind(HubInterface::class, static function () {
54+
return new Hub(null);
55+
});
56+
57+
$expectedData = [
58+
'enabled' => 'NOT CONFIGURED',
59+
'php_sdk_version' => Client::SDK_VERSION,
60+
'laravel_sdk_version' => Version::SDK_VERSION,
61+
];
62+
63+
$actualData = $this->runArtisanAboutAndReturnSentryData();
64+
65+
foreach ($expectedData as $key => $value) {
66+
$this->assertArrayHasKey($key, $actualData);
67+
$this->assertEquals($value, $actualData[$key]);
68+
}
69+
}
70+
71+
private function runArtisanAboutAndReturnSentryData(): array
72+
{
73+
$this->withoutMockingConsoleOutput();
74+
75+
$this->artisan(AboutCommand::class, ['--json' => null]);
76+
77+
$output = Artisan::output();
78+
79+
// This might seem like a weird thing to do, but it's necessary to make sure that that the command didn't have any side effects on the container
80+
$this->refreshApplication();
81+
82+
$aboutOutput = json_decode($output, true);
83+
84+
$this->assertArrayHasKey('sentry', $aboutOutput);
85+
86+
return $aboutOutput['sentry'];
87+
}
88+
}

0 commit comments

Comments
 (0)