forked from webgrip/telemetry-service
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'webgrip:main' into main
- Loading branch information
Showing
14 changed files
with
402 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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 |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
vendor/ | ||
var/ | ||
.composer/ | ||
.phpunit.cache/ | ||
.env | ||
*.private.env.json | ||
auth.json |
This file contains 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 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,13 @@ | ||
<?php | ||
|
||
namespace Webgrip\TelemetryService\Core\Domain\Attributes; | ||
|
||
use Attribute; | ||
|
||
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)] | ||
class Traceable | ||
{ | ||
public function __construct( | ||
public ?string $operationName = null | ||
) {} | ||
} |
This file contains 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 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,11 @@ | ||
<?php | ||
|
||
namespace Webgrip\TelemetryService\Core\Domain\Services; | ||
|
||
use OpenTelemetry\API\Trace\TracerInterface; | ||
|
||
interface TracingProxyInterface | ||
{ | ||
public function __construct(object $instance, TracerInterface $tracer); | ||
public function __call(string $method, array $arguments): mixed; | ||
} |
This file contains 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 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,31 @@ | ||
<?php | ||
|
||
namespace Webgrip\TelemetryService\Infrastructure\Factories; | ||
|
||
use ReflectionClass; | ||
use Webgrip\TelemetryService\Core\Domain\Attributes\Traceable; | ||
use Webgrip\TelemetryService\Core\Domain\Services\TelemetryServiceInterface; | ||
use Webgrip\TelemetryService\Infrastructure\Services\TracingProxy; | ||
|
||
class TracedClassFactory | ||
{ | ||
private TelemetryServiceInterface $telemetryService; | ||
|
||
public function __construct(TelemetryServiceInterface $telemetryService) | ||
{ | ||
$this->telemetryService = $telemetryService; | ||
} | ||
|
||
public function create(object $instance): object | ||
{ | ||
$reflectionClass = new ReflectionClass($instance); | ||
$hasTraceableAttribute = !empty($reflectionClass->getAttributes(Traceable::class)); | ||
|
||
if ($hasTraceableAttribute) { | ||
return new TracingProxy($instance, $this->telemetryService); | ||
} | ||
|
||
// If no Traceable attribute, return the instance directly | ||
return $instance; | ||
} | ||
} |
This file contains 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 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,77 @@ | ||
<?php | ||
|
||
namespace Webgrip\TelemetryService\Infrastructure\Services; | ||
|
||
use OpenTelemetry\API\Trace\SpanInterface; | ||
use ReflectionClass; | ||
use ReflectionMethod; | ||
use Webgrip\TelemetryService\Core\Domain\Attributes\Traceable; | ||
use Webgrip\TelemetryService\Core\Domain\Services\TelemetryServiceInterface; | ||
|
||
class TracingProxy | ||
{ | ||
public TelemetryServiceInterface $telemetryService; | ||
private object $instance; | ||
|
||
public SpanInterface $span; | ||
|
||
|
||
private bool $traceAllMethods; | ||
|
||
/** | ||
* @param object $instance | ||
* @param TelemetryServiceInterface $telemetryService | ||
*/ | ||
public function __construct(object $instance, TelemetryServiceInterface $telemetryService) | ||
{ | ||
$this->instance = $instance; | ||
$this->telemetryService = $telemetryService; | ||
|
||
// Check if the class itself is marked as Traceable | ||
$reflectionClass = new ReflectionClass($this->instance); | ||
$this->traceAllMethods = !empty($reflectionClass->getAttributes(Traceable::class)); | ||
} | ||
|
||
/** | ||
* @param string $method | ||
* @param array $arguments | ||
* @return mixed | ||
* @throws \ReflectionException | ||
* @throws \Throwable | ||
*/ | ||
public function __call(string $method, array $arguments) | ||
{ | ||
$reflectionMethod = new ReflectionMethod($this->instance, $method); | ||
$traceableAttributes = $reflectionMethod->getAttributes(Traceable::class); | ||
$traceableMethod = !empty($traceableAttributes); | ||
|
||
// Set operation name from attribute or use the method name as fallback | ||
$operationName = $method; | ||
if ($traceableMethod) { | ||
/** @var Traceable $traceableInstance */ | ||
$traceableInstance = $traceableAttributes[0]->newInstance(); | ||
$operationName = $traceableInstance->operationName ?? $method; | ||
} | ||
|
||
if ($this->traceAllMethods || $traceableMethod) { | ||
$this->span = $this->telemetryService->tracer() | ||
->spanBuilder($operationName) | ||
->startSpan(); | ||
|
||
$scope = $this->span->activate(); | ||
|
||
try { | ||
// Invoke the original method with the arguments | ||
return $reflectionMethod->invokeArgs($this->instance, $arguments); | ||
} catch (\Throwable $e) { | ||
$this->telemetryService->registerException($e, $this->span); | ||
throw $e; | ||
} finally { | ||
$scope->detach(); | ||
$this->span->end(); | ||
} | ||
} else { | ||
return $reflectionMethod->invokeArgs($this->instance, $arguments); | ||
} | ||
} | ||
} |
This file contains 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,11 @@ | ||
<?php | ||
|
||
namespace Webgrip\TelemetryService\Tests\Fixtures; | ||
|
||
class NonTraceableClass | ||
{ | ||
public function untracedMethod() | ||
{ | ||
// Simulate some logic | ||
} | ||
} |
This file contains 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,19 @@ | ||
<?php | ||
|
||
namespace Webgrip\TelemetryService\Tests\Fixtures; | ||
|
||
use Webgrip\TelemetryService\Core\Domain\Attributes\Traceable; | ||
|
||
class PartiallyTraceableClass | ||
{ | ||
#[Traceable] | ||
public function tracedMethod() | ||
{ | ||
// Simulate some logic | ||
} | ||
|
||
public function untracedMethod() | ||
{ | ||
// Simulate some logic | ||
} | ||
} |
This file contains 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,14 @@ | ||
<?php | ||
|
||
namespace Webgrip\TelemetryService\Tests\Fixtures; | ||
|
||
use Webgrip\TelemetryService\Core\Domain\Attributes\Traceable; | ||
|
||
#[Traceable] | ||
class TraceableClass | ||
{ | ||
public function tracedMethod() | ||
{ | ||
return 'traced'; | ||
} | ||
} |
This file contains 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,51 @@ | ||
<?php | ||
|
||
namespace Unit\Core\Domain\Attributes; | ||
|
||
use ReflectionClass; | ||
use ReflectionMethod; | ||
use Webgrip\TelemetryService\Core\Domain\Attributes\Traceable; | ||
use Webgrip\TelemetryService\Tests\Fixtures\NonTraceableClass; | ||
use Webgrip\TelemetryService\Tests\Fixtures\PartiallyTraceableClass; | ||
use Webgrip\TelemetryService\Tests\Fixtures\TraceableClass; | ||
use Webgrip\TelemetryService\Tests\Unit\TestCase; | ||
|
||
class TraceableTest extends TestCase | ||
{ | ||
public function testClassHasTraceableAttribute() | ||
{ | ||
$reflection = new ReflectionClass(TraceableClass::class); | ||
$attributes = $reflection->getAttributes(Traceable::class); | ||
|
||
$this->assertNotEmpty($attributes, "Class 'ExampleClass' should have Traceable attribute"); | ||
} | ||
|
||
public function testMethodHasTraceableAttribute() | ||
{ | ||
$partiallyTracableClass = new ReflectionClass(PartiallyTraceableClass::class); | ||
$tracedReflection = new ReflectionMethod(PartiallyTraceableClass::class, 'tracedMethod'); | ||
$untracedReflection = new ReflectionMethod(PartiallyTraceableClass::class, 'untracedMethod');; | ||
|
||
$this->assertEmpty( | ||
$partiallyTracableClass->getAttributes(Traceable::class), | ||
"Method 'tracedMethod' should have Traceable attribute" | ||
); | ||
|
||
$this->assertNotEmpty( | ||
$tracedReflection->getAttributes(Traceable::class), | ||
"Method 'tracedMethod' should have Traceable attribute" | ||
); | ||
$this->assertEmpty( | ||
$untracedReflection->getAttributes(Traceable::class), | ||
"Method 'tracedMethod' should have Traceable attribute" | ||
); | ||
} | ||
|
||
public function testMethodWithoutTraceableAttribute() | ||
{ | ||
$reflection = new ReflectionMethod(NonTraceableClass::class, 'untracedMethod'); | ||
$attributes = $reflection->getAttributes(Traceable::class); | ||
|
||
$this->assertEmpty($attributes, "Method 'untracedMethod' should not have Traceable attribute"); | ||
} | ||
} |
Oops, something went wrong.