diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4630d591..a3927ae4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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)
diff --git a/README.md b/README.md
index 30be5cbd..f1bd372d 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/composer.json b/composer.json
index cd152ece..3b422467 100644
--- a/composer.json
+++ b/composer.json
@@ -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/"
diff --git a/src/Sentry/Laravel/Integration.php b/src/Sentry/Laravel/Integration.php
index f400aaf5..aabe8f15 100644
--- a/src/Sentry/Laravel/Integration.php
+++ b/src/Sentry/Laravel/Integration.php
@@ -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;
@@ -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];
}
/**
@@ -247,7 +229,25 @@ public static function sentryTracingMeta(): string
}
$content = sprintf('', $span->toTraceparent());
- // $content .= sprintf('', $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('', $span->toBaggage());
return $content;
}
diff --git a/src/Sentry/Laravel/ServiceProvider.php b/src/Sentry/Laravel/ServiceProvider.php
index 596c4cac..9edb5015 100644
--- a/src/Sentry/Laravel/ServiceProvider.php
+++ b/src/Sentry/Laravel/ServiceProvider.php
@@ -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;
@@ -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);
@@ -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();
diff --git a/src/Sentry/Laravel/Tracing/Middleware.php b/src/Sentry/Laravel/Tracing/Middleware.php
index 24eb8341..460ec941 100644
--- a/src/Sentry/Laravel/Tracing/Middleware.php
+++ b/src/Sentry/Laravel/Tracing/Middleware.php
@@ -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
@@ -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
{
@@ -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([
@@ -180,30 +180,18 @@ 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
@@ -211,7 +199,7 @@ 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)) {
@@ -226,5 +214,6 @@ private function updateTransactionNameIfDefault(?string $name): void
}
$this->transaction->setName($name);
+ $this->transaction->getMetadata()->setSource($source ?? TransactionSource::custom());
}
}
diff --git a/src/Sentry/Laravel/Tracing/ServiceProvider.php b/src/Sentry/Laravel/Tracing/ServiceProvider.php
index 3235b3c4..336e6025 100644
--- a/src/Sentry/Laravel/Tracing/ServiceProvider.php
+++ b/src/Sentry/Laravel/Tracing/ServiceProvider.php
@@ -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;
@@ -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);
@@ -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
diff --git a/test/Sentry/IntegrationTest.php b/test/Sentry/IntegrationTest.php
index c116bfc2..34c98d27 100644
--- a/test/Sentry/IntegrationTest.php
+++ b/test/Sentry/IntegrationTest.php
@@ -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);
- }
}