diff --git a/composer.json b/composer.json index 50fbe1cc..836c9dfa 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ "php": ">=8.1", "monolog/monolog": "^2.0|^3.0", "psr/cache": "^3.0", - "psr/log": "^1.0|^2.0|^3.0" + "psr/log": "^1.0|^2.0|^3.0", + "ramsey/uuid": "^4.7" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.15.0", diff --git a/src/LaunchDarkly/Impl/Util.php b/src/LaunchDarkly/Impl/Util.php index 2f73ab51..05649307 100644 --- a/src/LaunchDarkly/Impl/Util.php +++ b/src/LaunchDarkly/Impl/Util.php @@ -120,6 +120,10 @@ public static function defaultHeaders(string $sdkKey, array $options): array } } + if (!empty($options['instance_id'])) { + $headers['X-LaunchDarkly-Instance-Id'] = $options['instance_id']; + } + return $headers; } diff --git a/src/LaunchDarkly/LDClient.php b/src/LaunchDarkly/LDClient.php index e8271b99..900cc1b3 100644 --- a/src/LaunchDarkly/LDClient.php +++ b/src/LaunchDarkly/LDClient.php @@ -25,6 +25,7 @@ use Monolog\Handler\ErrorLogHandler; use Monolog\Logger; use Psr\Log\LoggerInterface; +use Ramsey\Uuid\Uuid; /** * A client for the LaunchDarkly API. @@ -92,6 +93,17 @@ class LDClient */ public function __construct(string $sdkKey, array $options = []) { + $apcuLoaded = extension_loaded('apcu'); + + if ($apcuLoaded && \apcu_enabled()) { + $options['instance_id'] = \apcu_entry('ld::instanceid', function ($key) { + $uuid = Uuid::uuid4()->toString(); + return $uuid; + }); + } elseif (php_sapi_name() === 'cli') { + $options['instance_id'] = Uuid::uuid4()->toString(); + } + $this->_sdkKey = $sdkKey; if (!isset($options['base_uri'])) { $this->_baseUri = self::DEFAULT_BASE_URI; diff --git a/test-service/TestService.php b/test-service/TestService.php index 7b4cee7b..8b99e172 100644 --- a/test-service/TestService.php +++ b/test-service/TestService.php @@ -77,6 +77,7 @@ public function getStatus(): array 'migrations', 'event-sampling', 'inline-context-all', + 'instance-id', 'anonymous-redaction', 'client-prereq-events', 'big-segments' diff --git a/tests/Impl/Integrations/EventPublisherTest.php b/tests/Impl/Integrations/EventPublisherTest.php index 3d68f21c..d5539926 100644 --- a/tests/Impl/Integrations/EventPublisherTest.php +++ b/tests/Impl/Integrations/EventPublisherTest.php @@ -34,6 +34,7 @@ public function getEventPublisher(): array 'connect_timeout' => 3, 'application_info' => $appInfo, 'logger' => $logger, + 'instance_id' => 'my-instance-id', ]; $curlPublisher = new Integrations\CurlEventPublisher('sdk-key', $config); @@ -90,5 +91,6 @@ public function testSendsCorrectBodyAndHeaders($publisher) $this->assertEquals(EventPublisher::CURRENT_SCHEMA_VERSION, $headers['X-LaunchDarkly-Event-Schema']); $this->assertArrayHasKey('X-LaunchDarkly-Unsummarized', $headers); $this->assertEquals('application-id/my-id application-version/my-version', $headers['X-LaunchDarkly-Tags']); + $this->assertEquals('my-instance-id', $headers['X-LaunchDarkly-Instance-Id']); } } diff --git a/tests/Impl/Integrations/GuzzleFeatureRequesterTest.php b/tests/Impl/Integrations/GuzzleFeatureRequesterTest.php index ec74046a..3dc323b3 100644 --- a/tests/Impl/Integrations/GuzzleFeatureRequesterTest.php +++ b/tests/Impl/Integrations/GuzzleFeatureRequesterTest.php @@ -32,6 +32,7 @@ public function testSendsCorrectHeaders(): void 'timeout' => 3, 'connect_timeout' => 3, 'application_info' => $appInfo, + 'instance_id' => 'my-instance-id', ]; $requester = new GuzzleFeatureRequester('http://localhost:8080', 'sdk-key', $config); @@ -71,6 +72,7 @@ public function testSendsCorrectHeaders(): void $this->assertEquals('sdk-key', $headers['Authorization']); $this->assertEquals('PHPClient/' . LDClient::VERSION, $headers['User-Agent']); $this->assertEquals('application-id/my-id application-version/my-version', $headers['X-LaunchDarkly-Tags']); + $this->assertEquals('my-instance-id', $headers['X-LaunchDarkly-Instance-Id']); } public function wrapperProvider(): array