-
Notifications
You must be signed in to change notification settings - Fork 180
Initial implementation of sentry tracing with tests #423
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
eeb9cd4
Implementation of symfony events sentry tracing with tests
rjd22 86b5af5
Move Tracing class next to other tracing classes to keep things consi…
rjd22 815dffb
Add changes made to changelog
rjd22 58319f8
General code improvements and fix CR issues
ste93cry 56f7d9f
Prefill the transaction context with the data retrieved from the sent…
ste93cry 39891a4
Make the request tracing enableable
ste93cry b2500fb
Revert "Make the request tracing enableable"
ste93cry File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sentry\SentryBundle\EventListener; | ||
|
||
use Sentry\State\HubInterface; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\Routing\Route; | ||
|
||
abstract class AbstractTracingRequestListener | ||
{ | ||
/** | ||
* @var HubInterface The current hub | ||
*/ | ||
protected $hub; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param HubInterface $hub The current hub | ||
*/ | ||
public function __construct(HubInterface $hub) | ||
{ | ||
$this->hub = $hub; | ||
} | ||
|
||
/** | ||
* This method is called once a response for the current HTTP request is | ||
* created, but before it is sent off to the client. Its use is mainly for | ||
* gathering information like the HTTP status code and attaching them as | ||
* tags of the span/transaction. | ||
* | ||
* @param RequestListenerResponseEvent $event The event | ||
*/ | ||
public function handleKernelResponseEvent(RequestListenerResponseEvent $event): void | ||
{ | ||
/** @var Response $response */ | ||
$response = $event->getResponse(); | ||
$span = $this->hub->getSpan(); | ||
|
||
if (null === $span) { | ||
return; | ||
} | ||
|
||
$span->setHttpStatus($response->getStatusCode()); | ||
} | ||
|
||
/** | ||
* Gets the name of the route or fallback to the controller FQCN if the | ||
* route is anonymous (e.g. a subrequest). | ||
* | ||
* @param Request $request The HTTP request | ||
*/ | ||
protected function getRouteName(Request $request): string | ||
{ | ||
$route = $request->attributes->get('_route'); | ||
|
||
if ($route instanceof Route) { | ||
$route = $route->getPath(); | ||
} | ||
|
||
if (null === $route) { | ||
$route = $request->attributes->get('_controller'); | ||
|
||
if (\is_array($route) && \is_callable($route, true)) { | ||
$route = sprintf('%s::%s', \is_object($route[0]) ? get_debug_type($route[0]) : $route[0], $route[1]); | ||
} | ||
} | ||
|
||
return \is_string($route) ? $route : '<unknown>'; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sentry\SentryBundle\EventListener; | ||
|
||
use Sentry\Tracing\Transaction; | ||
use Sentry\Tracing\TransactionContext; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpKernel\Event\FinishRequestEvent; | ||
|
||
/** | ||
* This event listener acts on the master requests and starts a transaction | ||
* to report performance data to Sentry. It gathers useful data like the | ||
* HTTP status code of the response or the name of the route that handles | ||
* the request and add them as tags. | ||
*/ | ||
final class TracingRequestListener extends AbstractTracingRequestListener | ||
{ | ||
/** | ||
* This method is called for each subrequest handled by the framework and | ||
* starts a new {@see Transaction}. | ||
* | ||
* @param RequestListenerRequestEvent $event The event | ||
*/ | ||
public function handleKernelRequestEvent(RequestListenerRequestEvent $event): void | ||
{ | ||
if (!$event->isMasterRequest()) { | ||
return; | ||
} | ||
|
||
/** @var Request $request */ | ||
$request = $event->getRequest(); | ||
$requestStartTime = $request->server->get('REQUEST_TIME_FLOAT', microtime(true)); | ||
|
||
$context = TransactionContext::fromSentryTrace($request->headers->get('sentry-trace', '')); | ||
$context->setOp('http.server'); | ||
$context->setName(sprintf('%s %s%s%s', $request->getMethod(), $request->getSchemeAndHttpHost(), $request->getBaseUrl(), $request->getPathInfo())); | ||
$context->setStartTimestamp($requestStartTime); | ||
$context->setTags($this->getTags($request)); | ||
|
||
$this->hub->setSpan($this->hub->startTransaction($context)); | ||
} | ||
|
||
/** | ||
* This method is called for each request handled by the framework and | ||
* ends the tracing. | ||
* | ||
* @param FinishRequestEvent $event The event | ||
*/ | ||
public function handleKernelFinishRequestEvent(FinishRequestEvent $event): void | ||
{ | ||
if (!$event->isMasterRequest()) { | ||
return; | ||
} | ||
|
||
$transaction = $this->hub->getTransaction(); | ||
|
||
if (null === $transaction) { | ||
return; | ||
} | ||
|
||
$transaction->finish(); | ||
} | ||
|
||
/** | ||
* Gets the tags to attach to the transaction. | ||
* | ||
* @param Request $request The HTTP request | ||
* | ||
* @return array<string, string> | ||
*/ | ||
private function getTags(Request $request): array | ||
{ | ||
$client = $this->hub->getClient(); | ||
$tags = [ | ||
'net.host.port' => (string) $request->getPort(), | ||
'http.method' => $request->getMethod(), | ||
'http.url' => $request->getUri(), | ||
'http.flavor' => $this->getHttpFlavor($request), | ||
'route' => $this->getRouteName($request), | ||
]; | ||
|
||
if (false !== filter_var($request->getHost(), \FILTER_VALIDATE_IP)) { | ||
$tags['net.host.ip'] = $request->getHost(); | ||
} else { | ||
$tags['net.host.name'] = $request->getHost(); | ||
} | ||
|
||
if (null !== $request->getClientIp() && null !== $client && $client->getOptions()->shouldSendDefaultPii()) { | ||
$tags['net.peer.ip'] = $request->getClientIp(); | ||
} | ||
|
||
return $tags; | ||
} | ||
|
||
/** | ||
* Gets the HTTP flavor from the request. | ||
* | ||
* @param Request $request The HTTP request | ||
*/ | ||
protected function getHttpFlavor(Request $request): string | ||
{ | ||
$protocolVersion = $request->getProtocolVersion(); | ||
|
||
if (str_starts_with($protocolVersion, 'HTTP/')) { | ||
return substr($protocolVersion, \strlen('HTTP/')); | ||
ste93cry marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
return $protocolVersion; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sentry\SentryBundle\EventListener; | ||
|
||
use Sentry\Tracing\Span; | ||
use Sentry\Tracing\SpanContext; | ||
use Symfony\Component\HttpKernel\Event\FinishRequestEvent; | ||
|
||
/** | ||
* This event listener acts on the sub requests and starts a child span of the | ||
* current transaction to gather performance data for each of them. | ||
*/ | ||
final class TracingSubRequestListener extends AbstractTracingRequestListener | ||
{ | ||
/** | ||
* This method is called for each subrequest handled by the framework and | ||
* traces each by starting a new {@see Span}. | ||
* | ||
* @param SubRequestListenerRequestEvent $event The event | ||
*/ | ||
public function handleKernelRequestEvent(SubRequestListenerRequestEvent $event): void | ||
{ | ||
if ($event->isMasterRequest()) { | ||
return; | ||
} | ||
|
||
$request = $event->getRequest(); | ||
$span = $this->hub->getSpan(); | ||
|
||
if (null === $span) { | ||
return; | ||
} | ||
|
||
$spanContext = new SpanContext(); | ||
$spanContext->setOp('http.server'); | ||
$spanContext->setDescription(sprintf('%s %s%s%s', $request->getMethod(), $request->getSchemeAndHttpHost(), $request->getBaseUrl(), $request->getPathInfo())); | ||
$spanContext->setTags([ | ||
'http.method' => $request->getMethod(), | ||
'http.url' => $request->getUri(), | ||
'route' => $this->getRouteName($request), | ||
]); | ||
|
||
$this->hub->setSpan($span->startChild($spanContext)); | ||
} | ||
|
||
/** | ||
* This method is called for each subrequest handled by the framework and | ||
* ends the tracing. | ||
* | ||
* @param FinishRequestEvent $event The event | ||
*/ | ||
public function handleKernelFinishRequestEvent(FinishRequestEvent $event): void | ||
{ | ||
if ($event->isMasterRequest()) { | ||
return; | ||
} | ||
|
||
$span = $this->hub->getSpan(); | ||
|
||
if (null === $span) { | ||
return; | ||
} | ||
|
||
$span->finish(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.