Skip to content

Commit ac27b40

Browse files
authored
Rename the span name of Laravel HTTP requests to include the low cardinality route name if possible. (#219)
* Added low cardinality laravel route to the span name of the outer span * Added not found test, and added logic to always ensure leading slash is present * Add named route to route URI test * Suppress psalm non empty string
1 parent a93b6dd commit ac27b40

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

src/HttpInstrumentation.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Illuminate\Contracts\Http\Kernel;
88
use Illuminate\Http\Request;
9+
use Illuminate\Support\Facades\Route;
910
use OpenTelemetry\API\Globals;
1011
use OpenTelemetry\API\Instrumentation\CachedInstrumentation;
1112
use OpenTelemetry\API\Trace\Span;
@@ -79,6 +80,16 @@ public static function register(CachedInstrumentation $instrumentation): void
7980
$span->setAttribute(TraceAttributes::NETWORK_PROTOCOL_VERSION, $response->getProtocolVersion());
8081
$span->setAttribute(TraceAttributes::HTTP_RESPONSE_BODY_SIZE, $response->headers->get('Content-Length'));
8182
}
83+
if(($route = Route::getCurrentRoute()?->uri()) !== null) {
84+
$request = ($params[0] instanceof Request) ? $params[0] : null;
85+
86+
if (! str_starts_with($route, '/')) {
87+
$route = '/' . $route;
88+
}
89+
90+
/** @psalm-suppress ArgumentTypeCoercion */
91+
$span->updateName(sprintf('%s %s', $request?->method() ?? 'unknown', $route));
92+
}
8293

8394
$span->end();
8495
}

tests/Integration/LaravelInstrumentationTest.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ public function test_request_response(): void
2121
$this->assertEquals(200, $response->status());
2222
$this->assertCount(1, $this->storage);
2323
$span = $this->storage[0];
24-
$this->assertSame('GET', $span->getName());
25-
24+
$this->assertSame('GET /', $span->getName());
25+
2626
$response = Http::get('opentelemetry.io');
2727
$this->assertEquals(200, $response->status());
2828
$span = $this->storage[1];
@@ -47,7 +47,7 @@ public function test_cache_log_db(): void
4747
$this->assertEquals(200, $response->status());
4848
$this->assertCount(2, $this->storage);
4949
$span = $this->storage[1];
50-
$this->assertSame('GET', $span->getName());
50+
$this->assertSame('GET /hello', $span->getName());
5151
$this->assertSame('http://localhost/hello', $span->getAttributes()->get(TraceAttributes::URL_FULL));
5252
$this->assertCount(5, $span->getEvents());
5353
$this->assertSame('cache set', $span->getEvents()[0]->getName());
@@ -64,6 +64,28 @@ public function test_cache_log_db(): void
6464
$this->assertSame('sqlite', $span->getAttributes()->get('db.system'));
6565
}
6666

67+
public function test_low_cardinality_route_span_name(): void
68+
{
69+
$this->router()->get('/hello/{name}', fn () => null)->name('hello-name');
70+
71+
$this->assertCount(0, $this->storage);
72+
$response = $this->call('GET', '/hello/opentelemetry');
73+
$this->assertEquals(200, $response->status());
74+
$this->assertCount(1, $this->storage);
75+
$span = $this->storage[0];
76+
$this->assertSame('GET /hello/{name}', $span->getName());
77+
}
78+
79+
public function test_route_span_name_if_not_found(): void
80+
{
81+
$this->assertCount(0, $this->storage);
82+
$response = $this->call('GET', '/not-found');
83+
$this->assertEquals(404, $response->status());
84+
$this->assertCount(1, $this->storage);
85+
$span = $this->storage[0];
86+
$this->assertSame('GET', $span->getName());
87+
}
88+
6789
private function router(): Router
6890
{
6991
/** @psalm-suppress PossiblyNullReference */

0 commit comments

Comments
 (0)