Skip to content

Commit

Permalink
feat(laravel): adds laravel instrumentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
jcchavezs committed Jul 15, 2020
1 parent b3866a9 commit eea758e
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 3 deletions.
8 changes: 5 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
},
"require-dev": {
"guzzlehttp/psr7": "^1.6",
"illuminate/http": "^7.20",
"illuminate/routing": "^7.20",
"jcchavezs/httptest": "~0.2",
"middlewares/fast-route": "^1.2.1",
"middlewares/request-handler": "^1.4.0",
"phpstan/phpstan": "~0.12.28",
"phpunit/phpunit": "~7.5.20",
"psr/http-client": "^1.0",
"psr/http-server-middleware": "^1.0",
"middlewares/fast-route": "^1.2.1",
"middlewares/request-handler": "^1.4.0",
"squizlabs/php_codesniffer": "3.*"
},
"config": {
Expand Down Expand Up @@ -76,4 +78,4 @@
"dev-master": "2.0.x-dev"
}
}
}
}
43 changes: 43 additions & 0 deletions src/Zipkin/Instrumentation/Laravel/DefaultParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Zipkin\Instrumentation\Laravel;

use Zipkin\Tags;
use Zipkin\SpanCustomizer;
use Zipkin\Propagation\TraceContext;
use Zipkin\Instrumentation\Http\Server\Parser;
use Illuminate\Http\Response;
use Illuminate\Http\Request;

class DefaultParser implements Parser
{
/**
* @param Request $request
*/
public function spanName($request): string
{
return $request->route()->getName();
}

/**
* @param Request $request
*/
public function request($request, TraceContext $context, SpanCustomizer $span): void
{
$span->tag(Tags\HTTP_METHOD, $request->method());
$span->tag(Tags\HTTP_PATH, $request->path());
}

/**
* @param Response $response
*/
public function response($response, TraceContext $context, SpanCustomizer $span): void
{
$span->tag(Tags\HTTP_STATUS_CODE, (string) $response->getStatusCode());
if ($response->getStatusCode() > 399) {
$span->tag(Tags\ERROR, (string) $response->getStatusCode());
}
}
}
107 changes: 107 additions & 0 deletions src/Zipkin/Instrumentation/Laravel/Middleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace Zipkin\Instrumentation\Laravel;

use Zipkin\Tracing;
use Zipkin\Tracer;
use Zipkin\SpanCustomizerShield;
use Zipkin\Span;
use Zipkin\Propagation\TraceContext;
use Zipkin\Propagation\SamplingFlags;
use Zipkin\Propagation\DefaultSamplingFlags;
use Zipkin\Kind;
use Zipkin\Instrumentation\Laravel\Propagation\RequestHeaders;
use Zipkin\Instrumentation\Http\Server\HttpServerTracing;
use Throwable;
use Illuminate\Http\Request;
use Closure;

class Middleware
{
/**
* @var Tracer
*/
private $tracer;

/**
* @var callable(array):?bool
*/
private $extractor;

/**
* @var Parser
*/
private $parser;

/**
* @var (callable(Request):?bool)|null
*/
private $requestSampler;

public function __construct(HttpServerTracing $tracing)
{
$this->tracer = $tracing->getTracing()->getTracer();
$this->extractor = $tracing->getTracing()->getPropagation()->getExtractor(new RequestHeaders());
$this->parser = $tracing->getParser();
$this->requestSampler = $tracing->getRequestSampler();
}

public static function createFromTracing(Tracing $tracing): self
{
return new self(new HttpServerTracing($tracing, new DefaultParser));
}

public function handle(Request $request, Closure $next)
{
$extractedContext = ($this->extractor)($request);

$span = $this->nextSpan($extractedContext, $request);
$scopeCloser = $this->tracer->openScope($span);

if ($span->isNoop()) {
try {
return $next($request);
} finally {
$span->finish();
$scopeCloser();
}
}

$span->setKind(Kind\SERVER);
$spanCustomizer = new SpanCustomizerShield($span);
$span->setName($this->parser->spanName($request));
$this->parser->request($request, $span->getContext(), $spanCustomizer);

try {
$response = $next($request);
$this->parser->response($response, $span->getContext(), $spanCustomizer);
return $response;
} catch (Throwable $e) {
$span->setError($e);
throw $e;
} finally {
$span->finish();
$scopeCloser();
}
}

private function nextSpan(?SamplingFlags $extractedContext, Request $request): Span
{
if ($extractedContext instanceof TraceContext) {
return $this->tracer->joinSpan($extractedContext);
}

$extractedContext = $extractedContext ?? DefaultSamplingFlags::createAsEmpty();
if ($this->requestSampler === null) {
return $this->tracer->nextSpan($extractedContext);
}

return $this->tracer->nextSpanWithSampler(
$this->requestSampler,
[$request],
$extractedContext
);
}
}
21 changes: 21 additions & 0 deletions src/Zipkin/Instrumentation/Laravel/Propagation/RequestHeaders.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Zipkin\Instrumentation\Laravel\Propagation;

use Zipkin\Propagation\Getter;
use Illuminate\Http\Request;

final class RequestHeaders implements Getter
{
/**
* {@inheritdoc}
*
* @param Request $carrier
*/
public function get($carrier, string $key): ?string
{
return $carrier->hasHeader($key) ? $carrier->header($key)[0] : null;
}
}

0 comments on commit eea758e

Please sign in to comment.