Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
gaelreyrol committed Feb 29, 2024
1 parent 495c694 commit 4da1bcc
Show file tree
Hide file tree
Showing 27 changed files with 656 additions and 64 deletions.
17 changes: 13 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,12 @@
"ext-grpc": "*",
"ext-mbstring": "*",
"ext-opentelemetry": "*",
"ext-pdo": "*",
"ext-pdo_sqlite": "*",
"ext-xdebug": "*",
"doctrine/dbal": "^3.8",
"doctrine/doctrine-bundle": "^2.11",
"doctrine/doctrine-migrations-bundle": "^3.3",
"doctrine/orm": "^2.18",
"ergebnis/composer-normalize": "^2.42",
"friendsofphp/php-cs-fixer": "^3.49",
Expand All @@ -70,21 +73,22 @@
"phpunit/phpunit": "^10.5",
"pyrech/composer-changelogs": "^2.1",
"roave/security-advisories": "dev-master",
"symfony/browser-kit": "^7.0",
"symfony/cache": "^6.4 || ^7.0",
"symfony/framework-bundle": "^6.4 || ^7.0",
"symfony/http-kernel": "^6.4 || ^7.0",
"symfony/mailer": "^6.4 || ^7.0",
"symfony/messenger": "^6.4 || ^7.0",
"symfony/monolog-bundle": "^3.10",
"symfony/phpunit-bridge": "^6.4 || ^7.0",
"symfony/runtime": "^7.0",
"symfony/twig-bundle": "^6.4 || ^7.0",
"symfony/yaml": "^6.4 || ^7.0",
"twig/twig": "^3.8",
"zalas/phpunit-globals": "^3.2"
},
"suggest": {
"doctrine/dbal": "Needed to enable Doctrine DBAL instrumentation",
"doctrine/orm": "Needed to enable Doctrine ORM instrumentation",
"doctrine/doctrine-bundle": "Needed to enable Doctrine DBAL & ORM instrumentation",
"open-telemetry/exporter-otlp": "Needed to export OpenTelemetry data via OTPL",
"open-telemetry/exporter-zipkin": "Needed to export OpenTelemetry data via Zipkin",
"open-telemetry/opentelemetry-logger-monolog": "Need to export logs from Monolog via OpenTelemetry",
Expand All @@ -107,15 +111,17 @@
"autoload-dev": {
"psr-4": {
"FriendsOfOpenTelemetry\\OpenTelemetryBundle\\Tests\\": "tests/",
"FriendsOfOpenTelemetry\\OpenTelemetryBundle\\Tests\\Application\\": "tests/Application/src"
"FriendsOfOpenTelemetry\\OpenTelemetryBundle\\Tests\\Application\\": "tests/Application/src",
"FriendsOfOpenTelemetry\\OpenTelemetryBundle\\Tests\\Application\\Migrations\\": "tests/Application/migrations"
}
},
"config": {
"allow-plugins": {
"ergebnis/composer-normalize": true,
"php-http/discovery": true,
"phpstan/extension-installer": true,
"pyrech/composer-changelogs": true
"pyrech/composer-changelogs": true,
"symfony/runtime": true
},
"sort-packages": true
},
Expand All @@ -142,6 +148,9 @@
"test": [
"@putenv XDEBUG_MODE=off",
"@phpunit"
],
"test:console": [
"@php ./tests/Application/bin/console"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
use Doctrine\DBAL\Driver\Result;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use OpenTelemetry\API\Trace\SpanInterface;
use OpenTelemetry\Context\ScopeInterface;
use OpenTelemetry\SemConv\TraceAttributes;

class TraceableConnection extends AbstractConnectionMiddleware
{
public function __construct(
ConnectionInterface $connection,
private Tracer $tracer,
private ScopeInterface $driverScope,
private SpanInterface $driverSpan,
) {
parent::__construct($connection);
Expand All @@ -24,6 +26,7 @@ public function __construct(
*/
public function __destruct()
{
$this->driverScope->detach();
$this->driverSpan->end();
}

Expand Down
7 changes: 5 additions & 2 deletions src/Instrumentation/Doctrine/Middleware/TraceableDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@ public function connect(
->setAttribute(TraceAttributes::DB_USER, $params['user'])
;

$span = $spanBuilder->setParent(Context::getCurrent())->startSpan();
$parent = Context::getCurrent();

return new TraceableConnection(parent::connect($params), new Tracer($this->tracer), $span);
$span = $spanBuilder->setParent($parent)->startSpan();
$scope = $span->storeInContext($parent)->activate();

return new TraceableConnection(parent::connect($params), new Tracer($this->tracer), $scope, $span);
} catch (Exception $exception) {
$span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]);
$span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage());
Expand Down
10 changes: 1 addition & 9 deletions src/Instrumentation/Doctrine/Middleware/TraceableMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,18 @@
use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\Context\Context;
use Psr\Log\LoggerInterface;

final class TraceableMiddleware implements MiddlewareInterface
{
public function __construct(
private readonly TracerInterface $tracer,
private readonly LoggerInterface $logger,
private readonly ?LoggerInterface $logger = null,

Check failure on line 14 in src/Instrumentation/Doctrine/Middleware/TraceableMiddleware.php

View workflow job for this annotation

GitHub Actions / PHPStan (PHP 8.3)

Property FriendsOfOpenTelemetry\OpenTelemetryBundle\Instrumentation\Doctrine\Middleware\TraceableMiddleware::$logger is never read, only written.
) {
}

public function wrap(DriverInterface $driver): DriverInterface
{
$scope = Context::storage()->scope();
if (null === $scope) {
$this->logger->debug('No scope is available to register new spans.');

return $driver;
}

return new TraceableDriver($this->tracer, $driver);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function __construct(
private readonly TextMapPropagatorInterface $propagator,
private readonly PropagationGetterInterface $propagationGetter,
/** @phpstan-ignore-next-line */
private readonly LoggerInterface $logger,
private readonly ?LoggerInterface $logger = null,
iterable $requestHeaders = [],
iterable $responseHeaders = [],
) {
Expand Down
17 changes: 12 additions & 5 deletions src/Instrumentation/Twig/TraceableTwigExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\ScopeInterface;
use Twig\Extension\AbstractExtension;
use Twig\Profiler\NodeVisitor\ProfilerNodeVisitor;
use Twig\Profiler\Profile;
Expand All @@ -17,6 +18,8 @@ class TraceableTwigExtension extends AbstractExtension
*/
private \SplObjectStorage $spans;

private ?ScopeInterface $scope = null;

public function __construct(
private readonly TracerInterface $tracer,
) {
Expand All @@ -26,32 +29,36 @@ public function __construct(
public function enter(Profile $profile): void
{
$scope = Context::storage()->scope();
if (null === $scope) {
return;
}

$spanBuilder = $this->tracer
->spanBuilder($this->getSpanName($profile))
->setSpanKind(SpanKind::KIND_SERVER)
->setSpanKind(SpanKind::KIND_INTERNAL)
;

$parent = Context::getCurrent();

$span = $spanBuilder->setParent($parent)->startSpan();
if (null === $scope) {
$this->scope = $span->storeInContext($parent)->activate();
}

$this->spans[$profile] = $span;
}

public function leave(Profile $profile): void
{
$scope = Context::storage()->scope();
$scope = Context::storage()->scope() ?? $this->scope;
if (null === $scope) {
return;
}

if (!isset($this->spans[$profile])) {
return;
}
if (null !== $this->scope && 1 === count($this->spans)) {
$this->scope->detach();
$this->scope = null;
}
$this->spans[$profile]->end();
unset($this->spans[$profile]);
}
Expand Down
8 changes: 8 additions & 0 deletions tests/Application/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

namespace FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application;

use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
use FriendsOfOpenTelemetry\OpenTelemetryBundle\OpenTelemetryBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Bundle\MonologBundle\MonologBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
Expand All @@ -15,6 +19,10 @@ public function registerBundles(): iterable
{
return [
new FrameworkBundle(),
new DoctrineBundle(),
new DoctrineMigrationsBundle(),
new TwigBundle(),
new MonologBundle(),
new OpenTelemetryBundle(),
];
}
Expand Down
19 changes: 19 additions & 0 deletions tests/Application/bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env php

<?php

use FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;


if (!is_file(dirname(__DIR__).'/../../vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}

require_once dirname(__DIR__).'/../../vendor/autoload_runtime.php';

return function () {
$kernel = new Kernel('test', true);

return new Application($kernel);
};
18 changes: 18 additions & 0 deletions tests/Application/config/packages/doctrine.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
doctrine:
dbal:
url: 'sqlite:///%kernel.project_dir%/var/app.db'
profiling_collect_backtrace: '%kernel.debug%'
orm:
auto_generate_proxy_classes: true
enable_lazy_ghost_objects: true
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
report_fields_where_declared: true
mappings:
FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application\Entity'
alias: FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application
4 changes: 4 additions & 0 deletions tests/Application/config/packages/doctrine_migrations.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
doctrine_migrations:
migrations_paths:
'FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application\Migrations': '%kernel.project_dir%/migrations'
enable_profiler: false
1 change: 1 addition & 0 deletions tests/Application/config/packages/framework.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
framework:
secret: ThisIsSecret
test: true
fragments: { path: /_fragment }
3 changes: 3 additions & 0 deletions tests/Application/config/packages/monolog.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
monolog:
channels:
- deprecation
9 changes: 9 additions & 0 deletions tests/Application/config/packages/open_telemetry.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ open_telemetry:
console:
tracing:
enabled: true
doctrine:
tracing:
enabled: true
http_kernel:
tracing:
enabled: true
twig:
tracing:
enabled: true
traces:
tracers:
main:
Expand Down
2 changes: 2 additions & 0 deletions tests/Application/config/packages/twig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
twig:
default_path: '%kernel.project_dir%/templates'
27 changes: 27 additions & 0 deletions tests/Application/migrations/Version20240229075814.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240229075814 extends AbstractMigration
{
public function getDescription(): string
{
return 'Default schema';
}

public function up(Schema $schema): void
{
$this->addSql('CREATE TABLE dummy (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL COLLATE "BINARY")');
}

public function down(Schema $schema): void
{
$this->addSql('DROP TABLE dummy');
}
}
Empty file.
71 changes: 71 additions & 0 deletions tests/Application/src/Controller/DummyController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application\Controller;

use Doctrine\ORM\EntityManagerInterface;
use FriendsOfOpenTelemetry\OpenTelemetryBundle\Tests\Application\Entity\Dummy;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class DummyController extends AbstractController
{
#[Route('/ok', methods: ['GET'])]
public function ok(): Response
{
return $this->json([
'status' => 'ok',
]);
}

#[Route('/failure', methods: ['GET'])]
public function failure(): Response
{
return $this->json([
'status' => 'failure',
], Response::HTTP_SERVICE_UNAVAILABLE);
}

#[Route('/exception', methods: ['GET'])]
public function exception(): Response
{
throw new \RuntimeException('Oops');
}

#[Route('/view', methods: ['GET'])]
public function view(): Response
{
return $this->render('dummy.html.twig');
}

#[Route('/fragment', methods: ['GET'])]
public function segment(): Response
{
return $this->render('fragment.html.twig');
}

#[Route('/dummy/{dummy}', methods: ['GET'])]
public function viewDummy(Dummy $dummy): Response
{
return $this->json([
'id' => $dummy->id,
'name' => $dummy->name,
]);
}

#[Route('/dummy', methods: ['POST'])]
public function createDummy(EntityManagerInterface $entityManager, Request $request): Response
{
$name = $request->get('name');

$dummy = new Dummy(name: $name);
$entityManager->persist($dummy);
$entityManager->flush();

return $this->json([
'id' => $dummy->id,
'name' => $dummy->name,
]);
}
}
Loading

0 comments on commit 4da1bcc

Please sign in to comment.