Skip to content

Commit

Permalink
Drop Laravel Lumen support (#579)
Browse files Browse the repository at this point in the history
  • Loading branch information
cleptric committed Oct 13, 2022
1 parent acbf236 commit a733bbb
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 164 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Drop support for Laravel Lumen (#579)

## 2.14.2

- Fix extracting command input resulting in errors when calling Artisan commands programatically with `null` as an argument value (#589)
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -78,6 +78,7 @@ try {

## Laravel Version Compatibility

- Laravel Lumen is supported until `2.14.x`
- Laravel `<= 4.2.x` is supported until `0.8.x`
- Laravel `<= 5.7.x` on PHP `<= 7.0` is supported until `0.11.x`
- Laravel `>= 5.x.x` on PHP `>= 7.1` is supported in all versions
Expand Down
3 changes: 3 additions & 0 deletions composer.json
Expand Up @@ -28,6 +28,9 @@
"symfony/psr-http-message-bridge": "^1.0 | ^2.0",
"nyholm/psr7": "^1.0"
},
"conflict": {
"laravel/lumen-framework": "*"
},
"autoload": {
"psr-0": {
"Sentry\\Laravel\\": "src/"
Expand Down
84 changes: 42 additions & 42 deletions src/Sentry/Laravel/Integration.php
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Support\Str;
use Sentry\SentrySdk;
use Sentry\Tracing\Span;
use Sentry\Tracing\TransactionSource;
use function Sentry\addBreadcrumb;
use function Sentry\configureScope;
use Sentry\Breadcrumb;
Expand Down Expand Up @@ -122,67 +123,48 @@ public static function flushEvents(): void
* @param \Illuminate\Routing\Route $route
*
* @return string
*
* @internal This helper is used in various places to extra meaninful info from a Laravel Route object.
* @deprecated This will be removed in version 3.0, use `extractNameAndSourceForRoute` instead.
*/
public static function extractNameForRoute(Route $route): string
{
$routeName = null;

// someaction (route name/alias)
if ($route->getName()) {
$routeName = self::extractNameForNamedRoute($route->getName());
}

// Some\Controller@someAction (controller action)
if (empty($routeName) && $route->getActionName()) {
$routeName = self::extractNameForActionRoute($route->getActionName());
}

// /someaction // Fallback to the url
if (empty($routeName) || $routeName === 'Closure') {
$routeName = '/' . ltrim($route->uri(), '/');
}

return $routeName;
return self::extractNameAndSourceForRoute($route)[0];
}

/**
* Extract the readable name for a Lumen route.
* Extract the readable name for a route and the transaction source for where that route name came from.
*
* @param array $routeData The array of route data
* @param string $path The path of the request
* @param \Illuminate\Routing\Route $route
*
* @return string
* @return array{0: string, 1: \Sentry\Tracing\TransactionSource}
*
* @internal This helper is used in various places to extra meaninful info from a Laravel Route object.
*/
public static function extractNameForLumenRoute(array $routeData, string $path): string
public static function extractNameAndSourceForRoute(Route $route): array
{
$source = null;
$routeName = null;

$route = $routeData[1] ?? [];

// someaction (route name/alias)
if (!empty($route['as'])) {
$routeName = self::extractNameForNamedRoute($route['as']);
// some.action (route name/alias)
if ($route->getName()) {
$source = TransactionSource::component();
$routeName = self::extractNameForNamedRoute($route->getName());
}

// Some\Controller@someAction (controller action)
if (empty($routeName) && !empty($route['uses'])) {
$routeName = self::extractNameForActionRoute($route['uses']);
if (empty($routeName) && $route->getActionName()) {
$source = TransactionSource::component();
$routeName = self::extractNameForActionRoute($route->getActionName());
}

// /someaction // Fallback to the url
// /some/{action} // Fallback to the route uri (with parameter placeholders)
if (empty($routeName) || $routeName === 'Closure') {
$routeUri = array_reduce(
array_keys($routeData[2]),
static function ($carry, $key) use ($routeData) {
return str_replace($routeData[2][$key], "{{$key}}", $carry);
},
$path
);

$routeName = '/' . ltrim($routeUri, '/');
$source = TransactionSource::route();
$routeName = '/' . ltrim($route->uri(), '/');
}

return $routeName;
return [$routeName, $source];
}

/**
Expand Down Expand Up @@ -247,7 +229,25 @@ public static function sentryTracingMeta(): string
}

$content = sprintf('<meta name="sentry-trace" content="%s"/>', $span->toTraceparent());
// $content .= sprintf('<meta name="sentry-trace-data" content="%s"/>', $span->getDescription());

return $content;
}

/**
* Retrieve the meta tags with baggage information to link this request to front-end requests.
* This propagates the Dynamic Sampling Context.
*
* @return string
*/
public static function sentryBaggageMeta(): string
{
$span = self::currentTracingSpan();

if ($span === null) {
return '';
}

$content = sprintf('<meta name="baggage" content="%s"/>', $span->toBaggage());

return $content;
}
Expand Down
10 changes: 1 addition & 9 deletions src/Sentry/Laravel/ServiceProvider.php
Expand Up @@ -6,7 +6,6 @@
use Illuminate\Foundation\Application as Laravel;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Illuminate\Log\LogManager;
use Laravel\Lumen\Application as Lumen;
use RuntimeException;
use Sentry\ClientBuilder;
use Sentry\ClientBuilderInterface;
Expand Down Expand Up @@ -48,10 +47,7 @@ public function boot(): void
if ($this->hasDsnSet()) {
$this->bindEvents();

if ($this->app instanceof Lumen) {
$this->app->middleware(SetRequestMiddleware::class);
$this->app->middleware(SetRequestIpMiddleware::class);
} elseif ($this->app->bound(HttpKernelInterface::class)) {
if ($this->app->bound(HttpKernelInterface::class)) {
/** @var \Illuminate\Foundation\Http\Kernel $httpKernel */
$httpKernel = $this->app->make(HttpKernelInterface::class);

Expand All @@ -78,10 +74,6 @@ public function boot(): void
*/
public function register(): void
{
if ($this->app instanceof Lumen) {
$this->app->configure(static::$abstract);
}

$this->mergeConfigFrom(__DIR__ . '/../../../config/sentry.php', static::$abstract);

$this->configureAndRegisterClient();
Expand Down
37 changes: 13 additions & 24 deletions src/Sentry/Laravel/Tracing/Middleware.php
Expand Up @@ -11,6 +11,7 @@
use Sentry\Tracing\Span;
use Sentry\Tracing\SpanContext;
use Sentry\Tracing\TransactionContext;
use Sentry\Tracing\TransactionSource;
use Symfony\Component\HttpFoundation\Response;

class Middleware
Expand Down Expand Up @@ -90,9 +91,8 @@ public function terminate($request, $response): void
* @param float|null $timestamp The unix timestamp of the booted event, default to `microtime(true)` if not `null`.
*
* @return void
* @internal This method should only be invoked right after the application has finished "booting":
* For Laravel this is from the application `booted` callback.
* For Lumen this is right before returning from the `bootstrap/app.php` file.
*
* @internal This method should only be invoked right after the application has finished "booting".
*/
public function setBootedTimestamp(?float $timestamp = null): void
{
Expand All @@ -102,11 +102,11 @@ public function setBootedTimestamp(?float $timestamp = null): void
private function startTransaction(Request $request, HubInterface $sentry): void
{
$requestStartTime = $request->server('REQUEST_TIME_FLOAT', microtime(true));
$sentryTraceHeader = $request->header('sentry-trace');

$context = $sentryTraceHeader
? TransactionContext::fromSentryTrace($sentryTraceHeader)
: new TransactionContext;
$context = TransactionContext::fromHeaders(
$request->header('sentry-trace', ''),
$request->header('baggage', '')
);

$context->setOp('http.server');
$context->setData([
Expand Down Expand Up @@ -180,38 +180,26 @@ private function hydrateRequestData(Request $request): void
$route = $request->route();

if ($route instanceof Route) {
$this->updateTransactionNameIfDefault(
Integration::extractNameForRoute($route)
);
[$transactionName, $transactionSource] = Integration::extractNameAndSourceForRoute($route);

$this->updateTransactionNameIfDefault($transactionName, $transactionSource);

$this->transaction->setData([
'name' => $route->getName(),
'action' => $route->getActionName(),
'method' => $request->getMethod(),
]);
} elseif (is_array($route) && count($route) === 3) {
$this->updateTransactionNameIfDefault(
Integration::extractNameForLumenRoute($route, $request->path())
);

$action = $route[1] ?? [];

$this->transaction->setData([
'name' => $action['as'] ?? null,
'action' => $action['uses'] ?? 'Closure',
'method' => $request->getMethod(),
]);
}

$this->updateTransactionNameIfDefault('/' . ltrim($request->path(), '/'));
$this->updateTransactionNameIfDefault('/' . ltrim($request->path(), '/'), TransactionSource::url());
}

private function hydrateResponseData(Response $response): void
{
$this->transaction->setHttpStatus($response->getStatusCode());
}

private function updateTransactionNameIfDefault(?string $name): void
private function updateTransactionNameIfDefault(?string $name, ?TransactionSource $source): void
{
// Ignore empty names (and `null`) for caller convenience
if (empty($name)) {
Expand All @@ -226,5 +214,6 @@ private function updateTransactionNameIfDefault(?string $name): void
}

$this->transaction->setName($name);
$this->transaction->getMetadata()->setSource($source ?? TransactionSource::custom());
}
}
14 changes: 4 additions & 10 deletions src/Sentry/Laravel/Tracing/ServiceProvider.php
Expand Up @@ -6,11 +6,9 @@
use Illuminate\Contracts\View\Engine;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Illuminate\Queue\QueueManager;
use Illuminate\View\Engines\EngineResolver;
use Illuminate\View\Factory as ViewFactory;
use InvalidArgumentException;
use Laravel\Lumen\Application as Lumen;
use Sentry\Laravel\BaseServiceProvider;
use Sentry\Serializer\RepresentationSerializer;

Expand All @@ -29,9 +27,7 @@ public function boot(): void

$this->bindViewEngine($tracingConfig);

if ($this->app instanceof Lumen) {
$this->app->middleware(Middleware::class);
} elseif ($this->app->bound(HttpKernelInterface::class)) {
if ($this->app->bound(HttpKernelInterface::class)) {
/** @var \Illuminate\Foundation\Http\Kernel $httpKernel */
$httpKernel = $this->app->make(HttpKernelInterface::class);

Expand All @@ -55,11 +51,9 @@ public function register(): void
return new BacktraceHelper($options, new RepresentationSerializer($options));
});

if (!$this->app instanceof Lumen) {
$this->app->booted(function () {
$this->app->make(Middleware::class)->setBootedTimestamp();
});
}
$this->app->booted(function () {
$this->app->make(Middleware::class)->setBootedTimestamp();
});
}

private function bindEvents(array $tracingConfig): void
Expand Down
79 changes: 0 additions & 79 deletions test/Sentry/IntegrationTest.php
Expand Up @@ -162,83 +162,4 @@ public function testExtractingNameForRouteWithStrippedBaseNamespaceFromAction():

Integration::setControllersBaseNamespace(null);
}

public function testExtractingNameForLumenRouteWithName(): void
{
$route = [0, ['as' => $routeName = 'foo-bar'], []];

$this->assertSame($routeName, Integration::extractNameForLumenRoute($route, '/some-route'));
}

public function testExtractingNameForLumenRouteWithAction(): void
{
$route = [0, ['uses' => $controller = 'SomeController@someAction'], []];

$this->assertSame($controller, Integration::extractNameForLumenRoute($route, '/some-route'));
}

public function testExtractingNameForLumenRouteWithoutName(): void
{
$url = '/some-route';

$this->assertSame($url, Integration::extractNameForLumenRoute([0, [], []], $url));
}

public function testExtractingNameForLumenRouteWithParamInUrl(): void
{
$route = [1, [], ['param1' => 'foo']];

$url = '/foo/bar/baz';

$this->assertSame('/{param1}/bar/baz', Integration::extractNameForLumenRoute($route, $url));
}

public function testExtractingNameForLumenRouteWithParamsInUrl(): void
{
$route = [1, [], ['param1' => 'foo', 'param2' => 'bar']];

$url = '/foo/bar/baz';

$this->assertSame('/{param1}/{param2}/baz', Integration::extractNameForLumenRoute($route, $url));
}

public function testExtractingNameForLumenRouteWithActionAndName(): void
{
$route = [0, [
'as' => $routeName = 'foo-bar',
'uses' => 'SomeController@someAction',
], []];

$this->assertSame($routeName, Integration::extractNameForLumenRoute($route, '/some-route'));
}

public function testExtractingNameForLumenRouteWithAutoGeneratedName(): void
{
// We fake a generated name here, Laravel generates them each starting with `generated::`
$route = [0, ['as' => 'generated::KoAePbpBofo01ey4'], []];

$url = '/some-route';

$this->assertSame($url, Integration::extractNameForLumenRoute($route, $url));
}

public function testExtractingNameForLumenRouteWithIncompleteGroupName(): void
{
$route = [0, ['as' => 'group-name.'], []];

$url = '/some-route';

$this->assertSame($url, Integration::extractNameForLumenRoute($route, $url));
}

public function testExtractingNameForLumenRouteWithStrippedBaseNamespaceFromAction(): void
{
Integration::setControllersBaseNamespace('BaseNamespace');

$route = [0, ['uses' => 'BaseNamespace\\SomeController@someAction'], []];

$this->assertSame('SomeController@someAction', Integration::extractNameForLumenRoute($route, '/some-route'));

Integration::setControllersBaseNamespace(null);
}
}

0 comments on commit a733bbb

Please sign in to comment.