Skip to content

Commit

Permalink
Merge 919f550 into 9aa2609
Browse files Browse the repository at this point in the history
  • Loading branch information
Okhoshi committed Jul 22, 2023
2 parents 9aa2609 + 919f550 commit 627c7f2
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 110 deletions.
91 changes: 91 additions & 0 deletions src/Metrics/DefaultMetricsBucket.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace Unleash\Client\Metrics;

use DateTimeInterface;
use JetBrains\PhpStorm\ArrayShape;
use LogicException;

/**
* @internal
*/
final class DefaultMetricsBucket implements MetricsBucket
{
/**
* @var array<MetricsBucketToggle>
*/
private array $toggles = [];

public function __construct(
private readonly DateTimeInterface $startDate,
private ?DateTimeInterface $endDate = null,
) {
}

public function addToggle(MetricsBucketToggle $toggle): self
{
$this->toggles[] = $toggle;

return $this;
}

public function setStartDate(DateTimeInterface $date): self
{
throw new LogicException('Start date cannot be modified');
}

public function getStartDate(): DateTimeInterface
{
return $this->startDate;
}

public function setEndDate(?DateTimeInterface $endDate): self
{
$this->endDate = $endDate;

return $this;
}

public function getEndDate(): ?DateTimeInterface
{
return $this->endDate;
}

/**
* @return array<string,mixed>
*/
#[ArrayShape(['start' => 'string', 'stop' => 'string', 'toggles' => 'array'])]
public function jsonSerialize(): array
{
$togglesArray = [];

if ($this->endDate === null) {
throw new LogicException('Cannot serialize incomplete bucket');
}

foreach ($this->toggles as $toggle) {
$featureName = $toggle->getFeature()->getName();
if (!isset($togglesArray[$featureName])) {
$togglesArray[$featureName] = [
'yes' => 0,
'no' => 0,
];
}

$updateField = $toggle->isSuccess() ? 'yes' : 'no';
++$togglesArray[$featureName][$updateField];

if ($toggle->getVariant() !== null) {
$variant = $toggle->getVariant();
$togglesArray[$featureName]['variants'][$variant->getName()] ??= 0;
++$togglesArray[$featureName]['variants'][$variant->getName()];
}
}

return [
'start' => $this->startDate->format('c'),
'stop' => $this->endDate->format('c'),
'toggles' => $togglesArray,
];
}
}
34 changes: 34 additions & 0 deletions src/Metrics/DefaultMetricsBucketToggle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Unleash\Client\Metrics;

use Unleash\Client\DTO\Feature;
use Unleash\Client\DTO\Variant;

/**
* @internal
*/
final class DefaultMetricsBucketToggle implements MetricsBucketToggle
{
public function __construct(
private readonly Feature $feature,
private readonly bool $success,
private readonly ?Variant $variant = null,
) {
}

public function getFeature(): Feature
{
return $this->feature;
}

public function isSuccess(): bool
{
return $this->success;
}

public function getVariant(): ?Variant
{
return $this->variant;
}
}
14 changes: 7 additions & 7 deletions src/Metrics/DefaultMetricsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,30 @@ public function handleMetrics(Feature $feature, bool $successful, Variant $varia
}

$bucket = $this->getOrCreateBucket();
$bucket->addToggle(new MetricsBucketToggle($feature, $successful, $variant));
$bucket->addToggle(new DefaultMetricsBucketToggle($feature, $successful, $variant));
if ($this->shouldSend($bucket)) {
$this->send($bucket);
} else {
$this->store($bucket);
}
}

private function getOrCreateBucket(): MetricsBucket
private function getOrCreateBucket(): DefaultMetricsBucket
{
$cache = $this->configuration->getCache();

$bucket = null;
if ($cache->has(CacheKey::METRICS_BUCKET)) {
$bucket = $cache->get(CacheKey::METRICS_BUCKET);
assert($bucket instanceof MetricsBucket || $bucket === null);
assert($bucket instanceof DefaultMetricsBucket || $bucket === null);
}

$bucket ??= new MetricsBucket(new DateTimeImmutable());
$bucket ??= new DefaultMetricsBucket(new DateTimeImmutable());

return $bucket;
}

private function shouldSend(MetricsBucket $bucket): bool
private function shouldSend(DefaultMetricsBucket $bucket): bool
{
$bucketStartDate = $bucket->getStartDate();
$nowMilliseconds = (int) (microtime(true) * 1000);
Expand All @@ -58,7 +58,7 @@ private function shouldSend(MetricsBucket $bucket): bool
return $diff >= $this->configuration->getMetricsInterval();
}

private function send(MetricsBucket $bucket): void
private function send(DefaultMetricsBucket $bucket): void
{
$bucket->setEndDate(new DateTimeImmutable());
$this->metricsSender->sendMetrics($bucket);
Expand All @@ -68,7 +68,7 @@ private function send(MetricsBucket $bucket): void
}
}

private function store(MetricsBucket $bucket): void
private function store(DefaultMetricsBucket $bucket): void
{
$cache = $this->configuration->getCache();
$cache->set(CacheKey::METRICS_BUCKET, $bucket);
Expand Down
2 changes: 1 addition & 1 deletion src/Metrics/DefaultMetricsSender.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function sendMetrics(MetricsBucket $bucket): void
->withBody(new StringStream(json_encode([
'appName' => $this->configuration->getAppName(),
'instanceId' => $this->configuration->getInstanceId(),
'bucket' => $bucket->jsonSerialize(),
'bucket' => $bucket,
], JSON_THROW_ON_ERROR)));
foreach ($this->configuration->getHeaders() as $name => $value) {
$request = $request->withHeader($name, $value);
Expand Down
75 changes: 6 additions & 69 deletions src/Metrics/MetricsBucket.php
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -3,80 +3,17 @@
namespace Unleash\Client\Metrics;

use DateTimeInterface;
use JetBrains\PhpStorm\ArrayShape;
use JsonSerializable;
use LogicException;

/**
* @internal
*/
final class MetricsBucket implements JsonSerializable
interface MetricsBucket extends JsonSerializable
{
/**
* @var array<MetricsBucketToggle>
*/
private array $toggles = [];
public function getStartDate(): DateTimeInterface;

public function __construct(
private readonly DateTimeInterface $startDate,
private ?DateTimeInterface $endDate = null,
) {
}
public function setStartDate(DateTimeInterface $date): self;

public function addToggle(MetricsBucketToggle $toggle): self
{
$this->toggles[] = $toggle;
public function getEndDate(): ?DateTimeInterface;

return $this;
}
public function setEndDate(?DateTimeInterface $date): self;

public function getStartDate(): DateTimeInterface
{
return $this->startDate;
}

public function setEndDate(?DateTimeInterface $endDate): MetricsBucket
{
$this->endDate = $endDate;

return $this;
}

/**
* @return array<string,mixed>
*/
#[ArrayShape(['start' => 'string', 'stop' => 'string', 'toggles' => 'array'])]
public function jsonSerialize(): array
{
$togglesArray = [];

if ($this->endDate === null) {
throw new LogicException('Cannot serialize incomplete bucket');
}

foreach ($this->toggles as $toggle) {
$featureName = $toggle->getFeature()->getName();
if (!isset($togglesArray[$featureName])) {
$togglesArray[$featureName] = [
'yes' => 0,
'no' => 0,
];
}

$updateField = $toggle->isSuccess() ? 'yes' : 'no';
++$togglesArray[$featureName][$updateField];

if ($toggle->getVariant() !== null) {
$variant = $toggle->getVariant();
$togglesArray[$featureName]['variants'][$variant->getName()] ??= 0;
++$togglesArray[$featureName]['variants'][$variant->getName()];
}
}

return [
'start' => $this->startDate->format('c'),
'stop' => $this->endDate->format('c'),
'toggles' => $togglesArray,
];
}
public function addToggle(MetricsBucketToggle $toggle): self;
}
27 changes: 4 additions & 23 deletions src/Metrics/MetricsBucketToggle.php
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,11 @@
use Unleash\Client\DTO\Feature;
use Unleash\Client\DTO\Variant;

/**
* @internal
*/
final class MetricsBucketToggle
interface MetricsBucketToggle
{
public function __construct(
private readonly Feature $feature,
private readonly bool $success,
private readonly ?Variant $variant = null,
) {
}
public function getFeature(): Feature;

public function getFeature(): Feature
{
return $this->feature;
}
public function isSuccess(): bool;

public function isSuccess(): bool
{
return $this->success;
}

public function getVariant(): ?Variant
{
return $this->variant;
}
public function getVariant(): ?Variant;
}
12 changes: 6 additions & 6 deletions tests/Metrics/DefaultMetricsSenderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
use Unleash\Client\Configuration\UnleashConfiguration;
use Unleash\Client\DTO\DefaultFeature;
use Unleash\Client\DTO\DefaultVariant;
use Unleash\Client\Metrics\DefaultMetricsBucket;
use Unleash\Client\Metrics\DefaultMetricsBucketToggle;
use Unleash\Client\Metrics\DefaultMetricsSender;
use Unleash\Client\Metrics\MetricsBucket;
use Unleash\Client\Metrics\MetricsBucketToggle;
use Unleash\Client\Tests\AbstractHttpClientTest;

final class DefaultMetricsSenderTest extends AbstractHttpClientTest
Expand Down Expand Up @@ -39,9 +39,9 @@ public function testSendMetrics()
'Authorization' => 'test',
]);

$bucket = new MetricsBucket(new DateTimeImmutable(), new DateTimeImmutable());
$bucket = new DefaultMetricsBucket(new DateTimeImmutable(), new DateTimeImmutable());
$bucket
->addToggle(new MetricsBucketToggle(new DefaultFeature('test', true, []), true, null));
->addToggle(new DefaultMetricsBucketToggle(new DefaultFeature('test', true, []), true, null));

$this->pushResponse([], 1, 202);
$this->instance->sendMetrics($bucket);
Expand All @@ -53,7 +53,7 @@ public function testSendMetrics()

$this->configuration->setMetricsEnabled(true);
$bucket
->addToggle(new MetricsBucketToggle(
->addToggle(new DefaultMetricsBucketToggle(
new DefaultFeature('tet', true, []),
true,
new DefaultVariant('test', true)
Expand All @@ -65,7 +65,7 @@ public function testSendMetrics()
public function testSendMetricsFailure()
{
$this->pushResponse(new TransferException());
$bucket = new MetricsBucket(new DateTimeImmutable(), new DateTimeImmutable());
$bucket = new DefaultMetricsBucket(new DateTimeImmutable(), new DateTimeImmutable());
$this->instance->sendMetrics($bucket);
}
}
8 changes: 4 additions & 4 deletions tests/Metrics/MetricsBucketTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
use DateTimeImmutable;
use LogicException;
use PHPUnit\Framework\TestCase;
use Unleash\Client\Metrics\MetricsBucket;
use Unleash\Client\Metrics\DefaultMetricsBucket;

final class MetricsBucketTest extends TestCase
{
public function testJsonSerialize()
{
$instance = new MetricsBucket(new DateTimeImmutable(), new DateTimeImmutable());
$instance = new DefaultMetricsBucket(new DateTimeImmutable(), new DateTimeImmutable());
self::assertIsArray($instance->jsonSerialize());

$instance = new MetricsBucket(new DateTimeImmutable());
$instance = new DefaultMetricsBucket(new DateTimeImmutable());
$instance->setEndDate(new DateTimeImmutable());
self::assertIsArray($instance->jsonSerialize());

$instance = new MetricsBucket(new DateTimeImmutable());
$instance = new DefaultMetricsBucket(new DateTimeImmutable());
$this->expectException(LogicException::class);
$instance->jsonSerialize();
}
Expand Down

0 comments on commit 627c7f2

Please sign in to comment.