Skip to content

Commit

Permalink
feat: Add wrapper_name and wrapper_version configuration options (#207)
Browse files Browse the repository at this point in the history
  • Loading branch information
keelerm84 authored Jun 11, 2024
1 parent d4ea3ee commit 9deddf0
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/LaunchDarkly/Impl/Integrations/CurlEventPublisher.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function __construct(string $sdkKey, array $options = [])
$this->_curl = $options['curl'];
}

$this->_eventHeaders = Util::eventHeaders($sdkKey, $options['application_info'] ?? null);
$this->_eventHeaders = Util::eventHeaders($sdkKey, $options);
$this->_connectTimeout = $options['connect_timeout'];
$this->_isWindows = PHP_OS_FAMILY == 'Windows';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function __construct(string $sdkKey, array $options = [])
$this->_eventsUri = \LaunchDarkly\Impl\Util::adjustBaseUri($baseUri);

$this->_requestOptions = [
'headers' => Util::eventHeaders($this->_sdkKey, $options['application_info'] ?? null),
'headers' => Util::eventHeaders($this->_sdkKey, $options),
'timeout' => $options['timeout'],
'connect_timeout' => $options['connect_timeout']
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public function __construct(string $baseUri, string $sdkKey, array $options)
}

$defaults = [
'headers' => Util::defaultHeaders($sdkKey, $options['application_info'] ?? null),
'headers' => Util::defaultHeaders($sdkKey, $options),
'timeout' => $options['timeout'],
'connect_timeout' => $options['connect_timeout'],
'handler' => $stack,
Expand Down
19 changes: 14 additions & 5 deletions src/LaunchDarkly/Impl/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ public static function makeNullLogger(): LoggerInterface
* made to LaunchDarkly servers.
*
* @param string $sdkKey
* @param ApplicationInfo|null $applicationInfo
* @params array<string, mixed> $options
* @return array<string, string>
*/
public static function defaultHeaders(string $sdkKey, $applicationInfo): array
public static function defaultHeaders(string $sdkKey, array $options): array
{
$headers = [
'Content-Type' => 'application/json',
Expand All @@ -104,13 +104,22 @@ public static function defaultHeaders(string $sdkKey, $applicationInfo): array
'User-Agent' => 'PHPClient/' . LDClient::VERSION,
];

$applicationInfo = $options['application_info'] ?? null;
if ($applicationInfo instanceof ApplicationInfo) {
$headerValue = (string) $applicationInfo;
if ($headerValue) {
$headers['X-LaunchDarkly-Tags'] = $headerValue;
}
}

if (!empty($options['wrapper_name'])) {
$headers['X-LaunchDarkly-Wrapper'] = $options['wrapper_name'];

if (!empty($options['wrapper_version'])) {
$headers['X-LaunchDarkly-Wrapper'] .= '/' . $options['wrapper_version'];
}
}

return $headers;
}

Expand All @@ -119,12 +128,12 @@ public static function defaultHeaders(string $sdkKey, $applicationInfo): array
* made to the LaunchDarkly Events API.
*
* @param string $sdkKey
* @param ApplicationInfo|null $applicationInfo
* @param array<string, mixed> $options
* @return array
*/
public static function eventHeaders(string $sdkKey, $applicationInfo): array
public static function eventHeaders(string $sdkKey, array $options): array
{
$headers = Util::defaultHeaders($sdkKey, $applicationInfo);
$headers = Util::defaultHeaders($sdkKey, $options);
$headers['X-LaunchDarkly-Event-Schema'] = EventPublisher::CURRENT_SCHEMA_VERSION;
// Only the presence of this header is important. We encode a string
// value of 'true' to ensure it isn't dropped along the way.
Expand Down
2 changes: 2 additions & 0 deletions src/LaunchDarkly/LDClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class LDClient
* with this configuration active will have attributes with these names removed. You can also set private attributes on a
* - `application_info`: An optional {@see \LaunchDarkly\Types\ApplicationInfo} instance.
* per-user basis in the LDContext builder.
* - `wrapper_name`: For use by wrapper libraries to set an identifying name for the wrapper being used. This will be sent in User-Agent headers during requests to the LaunchDarkly servers to allow recording metrics on the usage of these wrapper libraries.
* - `wrapper_version`: For use by wrapper libraries to report the version of the library in use. If `wrapper_name` is not set, this field will be ignored. Otherwise the version string will be included in the User-Agent headers along with the `wrapper_name` during requests to the LaunchDarkly servers.
* - Other options may be available depending on any features you are using from the `LaunchDarkly\Integrations` namespace.
*
* @return LDClient
Expand Down
70 changes: 70 additions & 0 deletions tests/Impl/Integrations/GuzzleFeatureRequesterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,74 @@ public function testSendsCorrectHeaders(): void
$this->assertEquals('PHPClient/' . LDClient::VERSION, $headers['User-Agent']);
$this->assertEquals('application-id/my-id application-version/my-version', $headers['X-LaunchDarkly-Tags']);
}

public function wrapperProvider(): array
{
return [
[null, null, null],
['my-wrapper', null, 'my-wrapper'],
['my-wrapper', '1.0.0', 'my-wrapper/1.0.0'],
[null, '1.0.0', null],
];
}

/**
* @dataProvider wrapperProvider
*/
public function testSendsCorrectWrapperNameHeaders(?string $wrapper_name, ?string $wrapper_version, ?string $expected_header): void
{
/** @var LoggerInterface **/
$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();

$config = [
'logger' => $logger,
'timeout' => 3,
'connect_timeout' => 3,
];

if ($wrapper_name) {
$config['wrapper_name'] = $wrapper_name;
}
if ($wrapper_version) {
$config['wrapper_version'] = $wrapper_version;
}

$requester = new GuzzleFeatureRequester('http://localhost:8080', 'sdk-key', $config);
$requester->getFeature("flag-key");

$requests = [];
$client = new Client();

// Provide time for the curl to execute
$start = time();
while (time() - $start < 5) {
$response = $client->request('GET', 'http://localhost:8080/__admin/requests');
$body = json_decode($response->getBody()->getContents(), true);
$requests = $body['requests'];

if ($requests) {
break;
}
usleep(100);
}

if (!$requests) {
$this->fail("Unable to connect to endpoint within specified timeout");
}

$this->assertCount(1, $requests);

$request = $requests[0]['request'];

// Validate that we hit the right endpoint
$this->assertEquals('/sdk/flags/flag-key', $request['url']);

// And validate that we provided all the correct headers
$headers = $request['headers'];
if ($expected_header) {
$this->assertEquals($expected_header, $headers['X-LaunchDarkly-Wrapper']);
} else {
$this->assertNotContains('X-LaunchDarkly-Wrapper', $headers);
}
}
}

0 comments on commit 9deddf0

Please sign in to comment.