Skip to content

Commit bbf6cc6

Browse files
committed
feat(laravel): adds laravel instrumentation.
1 parent 04b36a6 commit bbf6cc6

File tree

4 files changed

+176
-3
lines changed

4 files changed

+176
-3
lines changed

composer.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@
2727
},
2828
"require-dev": {
2929
"guzzlehttp/psr7": "^1.6",
30+
"illuminate/http": "^7.20",
31+
"illuminate/routing": "^7.20",
3032
"jcchavezs/httptest": "~0.2",
33+
"middlewares/fast-route": "^1.2.1",
34+
"middlewares/request-handler": "^1.4.0",
3135
"phpstan/phpstan": "~0.12.28",
3236
"phpunit/phpunit": "~7.5.20",
3337
"psr/http-client": "^1.0",
3438
"psr/http-server-middleware": "^1.0",
35-
"middlewares/fast-route": "^1.2.1",
36-
"middlewares/request-handler": "^1.4.0",
3739
"squizlabs/php_codesniffer": "3.*"
3840
},
3941
"config": {
@@ -76,4 +78,4 @@
7678
"dev-master": "2.0.x-dev"
7779
}
7880
}
79-
}
81+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Zipkin\Instrumentation\Laravel;
6+
7+
use Zipkin\Tags;
8+
use Zipkin\SpanCustomizer;
9+
use Zipkin\Propagation\TraceContext;
10+
use Zipkin\Instrumentation\Http\Server\Parser;
11+
use Illuminate\Http\Response;
12+
use Illuminate\Http\Request;
13+
14+
class DefaultParser implements Parser
15+
{
16+
/**
17+
* @param Request $request
18+
*/
19+
public function spanName($request): string
20+
{
21+
return $request->route()->getName();
22+
}
23+
24+
/**
25+
* @param Request $request
26+
*/
27+
public function request($request, TraceContext $context, SpanCustomizer $span): void
28+
{
29+
$span->tag(Tags\HTTP_METHOD, $request->method());
30+
$span->tag(Tags\HTTP_PATH, $request->path());
31+
}
32+
33+
/**
34+
* @param Response $response
35+
*/
36+
public function response($response, TraceContext $context, SpanCustomizer $span): void
37+
{
38+
$span->tag(Tags\HTTP_STATUS_CODE, (string) $response->getStatusCode());
39+
if ($response->getStatusCode() > 399) {
40+
$span->tag(Tags\ERROR, (string) $response->getStatusCode());
41+
}
42+
}
43+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Zipkin\Instrumentation\Laravel;
6+
7+
use Zipkin\Tracing;
8+
use Zipkin\Tracer;
9+
use Zipkin\SpanCustomizerShield;
10+
use Zipkin\Span;
11+
use Zipkin\Propagation\TraceContext;
12+
use Zipkin\Propagation\SamplingFlags;
13+
use Zipkin\Propagation\DefaultSamplingFlags;
14+
use Zipkin\Kind;
15+
use Zipkin\Instrumentation\Laravel\Propagation\RequestHeaders;
16+
use Zipkin\Instrumentation\Http\Server\HttpServerTracing;
17+
use Throwable;
18+
use Illuminate\Http\Request;
19+
use Closure;
20+
21+
class Middleware
22+
{
23+
/**
24+
* @var Tracer
25+
*/
26+
private $tracer;
27+
28+
/**
29+
* @var callable(array):?bool
30+
*/
31+
private $extractor;
32+
33+
/**
34+
* @var Parser
35+
*/
36+
private $parser;
37+
38+
/**
39+
* @var (callable(Request):?bool)|null
40+
*/
41+
private $requestSampler;
42+
43+
public function __construct(HttpServerTracing $tracing)
44+
{
45+
$this->tracer = $tracing->getTracing()->getTracer();
46+
$this->extractor = $tracing->getTracing()->getPropagation()->getExtractor(new RequestHeaders());
47+
$this->parser = $tracing->getParser();
48+
$this->requestSampler = $tracing->getRequestSampler();
49+
}
50+
51+
public static function createFromTracing(Tracing $tracing): self
52+
{
53+
return new self(new HttpServerTracing($tracing, new DefaultParser));
54+
}
55+
56+
public function handle(Request $request, Closure $next)
57+
{
58+
$extractedContext = ($this->extractor)($request);
59+
60+
$span = $this->nextSpan($extractedContext, $request);
61+
$scopeCloser = $this->tracer->openScope($span);
62+
63+
if ($span->isNoop()) {
64+
try {
65+
return $next($request);
66+
} finally {
67+
$span->finish();
68+
$scopeCloser();
69+
}
70+
}
71+
72+
$span->setKind(Kind\SERVER);
73+
$spanCustomizer = new SpanCustomizerShield($span);
74+
$span->setName($this->parser->spanName($request));
75+
$this->parser->request($request, $span->getContext(), $spanCustomizer);
76+
77+
try {
78+
$response = $next($request);
79+
$this->parser->response($response, $span->getContext(), $spanCustomizer);
80+
return $response;
81+
} catch (Throwable $e) {
82+
$span->setError($e);
83+
throw $e;
84+
} finally {
85+
$span->finish();
86+
$scopeCloser();
87+
}
88+
}
89+
90+
private function nextSpan(?SamplingFlags $extractedContext, Request $request): Span
91+
{
92+
if ($extractedContext instanceof TraceContext) {
93+
return $this->tracer->joinSpan($extractedContext);
94+
}
95+
96+
$extractedContext = $extractedContext ?? DefaultSamplingFlags::createAsEmpty();
97+
if ($this->requestSampler === null) {
98+
return $this->tracer->nextSpan($extractedContext);
99+
}
100+
101+
return $this->tracer->nextSpanWithSampler(
102+
$this->requestSampler,
103+
[$request],
104+
$extractedContext
105+
);
106+
}
107+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Zipkin\Instrumentation\Laravel\Propagation;
6+
7+
use Zipkin\Propagation\Getter;
8+
use Illuminate\Http\Request;
9+
10+
final class RequestHeaders implements Getter
11+
{
12+
/**
13+
* {@inheritdoc}
14+
*
15+
* @param Request $carrier
16+
*/
17+
public function get($carrier, string $key): ?string
18+
{
19+
return $carrier->hasHeader($key) ? $carrier->header($key)[0] : null;
20+
}
21+
}

0 commit comments

Comments
 (0)