diff --git a/.phan/config.php b/.phan/config.php index d8c6d47e0..6fe91daf4 100644 --- a/.phan/config.php +++ b/.phan/config.php @@ -378,6 +378,7 @@ 'vendor/phan/phan/src/Phan', 'vendor/phpunit/phpunit/src', 'vendor/google/protobuf/src', + 'vendor/ramsey/uuid/src', ], // A list of individual files to include in analysis diff --git a/composer.json b/composer.json index 1c9b86703..40567c6eb 100644 --- a/composer.json +++ b/composer.json @@ -10,11 +10,12 @@ "php": "^8.1", "google/protobuf": "^3.22", "php-http/discovery": "^1.14", + "psr/http-client": "^1.0", "psr/http-client-implementation": "^1.0", "psr/http-factory-implementation": "^1.0", - "psr/http-client": "^1.0", "psr/http-message": "^1.0.1|^2.0", "psr/log": "^1.1|^2.0|^3.0", + "ramsey/uuid": "^3.0 || ^4.0", "symfony/config": "^5.4 || ^6.4 || ^7.0", "symfony/polyfill-mbstring": "^1.23", "symfony/polyfill-php82": "^1.26", diff --git a/deptrac.yaml b/deptrac.yaml index eb2f363e7..f9ad414d9 100644 --- a/deptrac.yaml +++ b/deptrac.yaml @@ -79,12 +79,16 @@ deptrac: regex: ^Composer\\* - name: HttpClients collectors: - - type: className - value: ^Symfony\\Component\\HttpClient\\* - - type: className - value: ^GuzzleHttp\\* - - type: className - value: ^Buzz\\* + - type: className + value: ^Symfony\\Component\\HttpClient\\* + - type: className + value: ^GuzzleHttp\\* + - type: className + value: ^Buzz\\* + - name: RamseyUuid + collectors: + - type: className + regex: ^Ramsey\\Uuid\\* ruleset: Context: @@ -100,6 +104,7 @@ deptrac: - HttpPlug - Composer - HttpClients + - RamseyUuid Contrib: - +SDK - +OtelProto diff --git a/src/SDK/Common/Configuration/KnownValues.php b/src/SDK/Common/Configuration/KnownValues.php index a7636214c..9c1626ef2 100644 --- a/src/SDK/Common/Configuration/KnownValues.php +++ b/src/SDK/Common/Configuration/KnownValues.php @@ -192,6 +192,7 @@ interface KnownValues public const VALUE_DETECTORS_PROCESS_RUNTIME = 'process_runtime'; public const VALUE_DETECTORS_SDK = 'sdk'; public const VALUE_DETECTORS_SDK_PROVIDED = 'sdk_provided'; + public const VALUE_DETECTORS_SERVICE = 'service'; public const VALUE_DETECTORS_COMPOSER = 'composer'; public const OTEL_PHP_DETECTORS = [ self::VALUE_ALL, diff --git a/src/SDK/Resource/Detectors/Service.php b/src/SDK/Resource/Detectors/Service.php new file mode 100644 index 000000000..b51920b4b --- /dev/null +++ b/src/SDK/Resource/Detectors/Service.php @@ -0,0 +1,29 @@ +toString(); + + $attributes = [ + ResourceAttributes::SERVICE_INSTANCE_ID => $serviceInstanceId, + ]; + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } +} diff --git a/src/SDK/Resource/ResourceInfoFactory.php b/src/SDK/Resource/ResourceInfoFactory.php index 507d967de..62759ddb0 100644 --- a/src/SDK/Resource/ResourceInfoFactory.php +++ b/src/SDK/Resource/ResourceInfoFactory.php @@ -42,6 +42,10 @@ public static function defaultResource(): ResourceInfo foreach ($detectors as $detector) { switch ($detector) { + case Values::VALUE_DETECTORS_SERVICE: + $resourceDetectors[] = new Detectors\Service(); + + break; case Values::VALUE_DETECTORS_ENVIRONMENT: $resourceDetectors[] = new Detectors\Environment(); diff --git a/src/SDK/composer.json b/src/SDK/composer.json index b84b94aa5..1c16a0046 100644 --- a/src/SDK/composer.json +++ b/src/SDK/composer.json @@ -28,6 +28,7 @@ "psr/http-client": "^1.0", "psr/http-message": "^1.0.1|^2.0", "psr/log": "^1.1|^2.0|^3.0", + "ramsey/uuid": "^3.0 || ^4.0", "symfony/polyfill-mbstring": "^1.23", "symfony/polyfill-php82": "^1.26" }, diff --git a/tests/Unit/SDK/Resource/Detectors/CompositeTest.php b/tests/Unit/SDK/Resource/Detectors/CompositeTest.php index c2187fc53..3f9202c99 100644 --- a/tests/Unit/SDK/Resource/Detectors/CompositeTest.php +++ b/tests/Unit/SDK/Resource/Detectors/CompositeTest.php @@ -6,14 +6,25 @@ use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Resource\Detectors\Composite; +use OpenTelemetry\SDK\Resource\Detectors\Environment; +use OpenTelemetry\SDK\Resource\Detectors\Service; use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SemConv\ResourceAttributes; +use OpenTelemetry\Tests\TestState; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; #[CoversClass(Composite::class)] class CompositeTest extends TestCase { + use TestState; + + public function tearDown(): void + { + $this->restoreEnvironmentVariables(); + } + public function test_composite_with_empty_resource_detectors(): void { $resourceDetector = new Composite([]); @@ -36,4 +47,15 @@ public function test_composite_get_resource(): void $this->assertSame('user-bar', $resource->getAttributes()->get('bar')); $this->assertNull($resource->getSchemaUrl()); } + + public function test_composite_get_resource_with_service_instance_id_from_resource_attributes() + { + $this->setEnvironmentVariable('OTEL_RESOURCE_ATTRIBUTES', 'service.instance.id=manual-id'); + $resouceDetector = new Composite([ + new Service(), + new Environment(), + ]); + $resource = $resouceDetector->getResource(); + $this->assertSame('manual-id', $resource->getAttributes()->get(ResourceAttributes::SERVICE_INSTANCE_ID)); + } } diff --git a/tests/Unit/SDK/Resource/Detectors/ServiceTest.php b/tests/Unit/SDK/Resource/Detectors/ServiceTest.php new file mode 100644 index 000000000..da5c1133e --- /dev/null +++ b/tests/Unit/SDK/Resource/Detectors/ServiceTest.php @@ -0,0 +1,41 @@ +detector = new Detectors\Service(); + } + + public function test_service_get_resource_with_default_service_instance_id(): void + { + $resource = $this->detector->getResource(); + + $this->assertNotEmpty($resource->getAttributes()); + + $id = $resource->getAttributes()->get(ResourceAttributes::SERVICE_INSTANCE_ID); + $this->assertMatchesRegularExpression(self::UUID_REGEX, $id); + } + + public function test_service_get_resource_multiple_calls_same_service_instance_id(): void + { + $resource1 = $this->detector->getResource(); + $resource2 = $this->detector->getResource(); + + $this->assertSame($resource1->getAttributes()->get(ResourceAttributes::SERVICE_INSTANCE_ID), $resource2->getAttributes()->get(ResourceAttributes::SERVICE_INSTANCE_ID)); + } +} diff --git a/tests/Unit/SDK/Resource/ResourceInfoFactoryTest.php b/tests/Unit/SDK/Resource/ResourceInfoFactoryTest.php index b046c0718..bb4d6a80e 100644 --- a/tests/Unit/SDK/Resource/ResourceInfoFactoryTest.php +++ b/tests/Unit/SDK/Resource/ResourceInfoFactoryTest.php @@ -154,7 +154,7 @@ public function test_composite_default_with_extra_resource_from_registry(): void public function test_default_with_all_sdk_detectors(): void { - $this->setEnvironmentVariable('OTEL_PHP_DETECTORS', 'env,host,os,process,process_runtime,sdk,sdk_provided,composer'); + $this->setEnvironmentVariable('OTEL_PHP_DETECTORS', 'service,env,host,os,process,process_runtime,sdk,sdk_provided,composer'); $resource = ResourceInfoFactory::defaultResource(); $keys = array_keys($resource->getAttributes()->toArray()); foreach (['service.name', 'telemetry.sdk.name', 'process.runtime.name', 'process.pid', 'host.arch'] as $key) {