From d41426fb9761724e37a07fc1e6a088a1f7ec8be0 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Thu, 11 Jul 2024 15:08:28 -0400 Subject: [PATCH 1/8] add events --- src/Adapters/EventDispatchingStatsRecord.php | 69 ++++++++++++++++++++ src/Events/CountRecordedEvent.php | 7 ++ src/Events/DistributionRecordedEvent.php | 7 ++ src/Events/GaugeRecordedEvent.php | 7 ++ src/Events/HistogramRecordedEvent.php | 7 ++ src/Events/SetRecordedEvent.php | 7 ++ src/Events/StatRecordedEvent.php | 15 +++++ src/Events/TimingRecordedEvent.php | 7 ++ 8 files changed, 126 insertions(+) create mode 100644 src/Adapters/EventDispatchingStatsRecord.php create mode 100644 src/Events/CountRecordedEvent.php create mode 100644 src/Events/DistributionRecordedEvent.php create mode 100644 src/Events/GaugeRecordedEvent.php create mode 100644 src/Events/HistogramRecordedEvent.php create mode 100644 src/Events/SetRecordedEvent.php create mode 100644 src/Events/StatRecordedEvent.php create mode 100644 src/Events/TimingRecordedEvent.php diff --git a/src/Adapters/EventDispatchingStatsRecord.php b/src/Adapters/EventDispatchingStatsRecord.php new file mode 100644 index 0000000..acb6e8b --- /dev/null +++ b/src/Adapters/EventDispatchingStatsRecord.php @@ -0,0 +1,69 @@ +dispatcher = $dispatcher; + + parent::__construct(); + } + + public function recordTiming(InMemoryTimingRecord $inMemoryTimingRecord): void + { + $this->dispatch(new TimingRecordedEvent($inMemoryTimingRecord)); + } + + public function recordCount(InMemoryCountRecord $inMemoryCountRecord): void + { + $this->dispatch(new CountRecordedEvent($inMemoryCountRecord)); + } + + + public function recordGauge(InMemoryGaugeRecord $inMemoryGaugeRecord): void + { + $this->dispatch(new GaugeRecordedEvent($inMemoryGaugeRecord)); + } + + public function recordSet(InMemorySetRecord $inMemorySetRecord): void + { + $this->dispatch(new SetRecordedEvent($inMemorySetRecord)); + } + + + public function recordHistogram(InMemoryHistogramRecord $inMemoryHistogramRecord): void + { + $this->dispatch(new HistogramRecordedEvent($inMemoryHistogramRecord)); + } + + public function recordDistribution(InMemoryDistributionRecord $inMemoryDistributionRecord): void + { + $this->dispatch(new DistributionRecordedEvent($inMemoryDistributionRecord)); + } + + + protected function dispatch(StatRecordedEvent $statRecordedEvent): void + { + $this->dispatcher->dispatch($statRecordedEvent); + } +} diff --git a/src/Events/CountRecordedEvent.php b/src/Events/CountRecordedEvent.php new file mode 100644 index 0000000..c0506e0 --- /dev/null +++ b/src/Events/CountRecordedEvent.php @@ -0,0 +1,7 @@ + Date: Thu, 11 Jul 2024 15:10:19 -0400 Subject: [PATCH 2/8] event adapter creator --- src/AdapterManager.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/AdapterManager.php b/src/AdapterManager.php index e59ba1a..97adda4 100644 --- a/src/AdapterManager.php +++ b/src/AdapterManager.php @@ -4,6 +4,7 @@ use Carbon\FactoryImmutable; use Carbon\WrapperClock; +use Cosmastech\LaravelStatsDAdapter\Adapters\EventDispatchingStatsRecord; use Cosmastech\StatsDClientAdapter\Adapters\Datadog\DatadogStatsDClientAdapter; use Cosmastech\StatsDClientAdapter\Adapters\InMemory\InMemoryClientAdapter; use Cosmastech\StatsDClientAdapter\Adapters\League\LeagueStatsDClientAdapter; @@ -180,6 +181,20 @@ protected function createLeagueAdapter(array $config): LeagueStatsDClientAdapter ); } + /** + * @param array $config + * @return InMemoryClientAdapter + * @throws BindingResolutionException + */ + protected function createEventAdapter(array $config): InMemoryClientAdapter + { + return new InMemoryClientAdapter( + $this->getDefaultTags(), + new EventDispatchingStatsRecord($this->app->make('events')), + clock: $this->getClockImplementation() + ); + } + protected function getClockImplementation(): ClockInterface { return new WrapperClock(FactoryImmutable::getDefaultInstance()); From 35062e1b65acaff94cd9f4b635330578bc664ed6 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Fri, 12 Jul 2024 08:31:00 -0400 Subject: [PATCH 3/8] adds event to config --- config/statsd-adapter.php | 4 ++++ src/Adapters/EventDispatchingStatsRecord.php | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config/statsd-adapter.php b/config/statsd-adapter.php index 30b1a24..e9cc6f3 100644 --- a/config/statsd-adapter.php +++ b/config/statsd-adapter.php @@ -14,11 +14,15 @@ * league * datadog * log_datadog + * event */ "channels" => [ "memory" => [ "adapter" => "memory", ], + "event" => [ + "adapter" => "event", + ], "league" => [ // see configuration options: https://github.com/thephpleague/statsd?tab=readme-ov-file#configuring "adapter" => "league", diff --git a/src/Adapters/EventDispatchingStatsRecord.php b/src/Adapters/EventDispatchingStatsRecord.php index acb6e8b..49a9d6d 100644 --- a/src/Adapters/EventDispatchingStatsRecord.php +++ b/src/Adapters/EventDispatchingStatsRecord.php @@ -39,7 +39,6 @@ public function recordCount(InMemoryCountRecord $inMemoryCountRecord): void $this->dispatch(new CountRecordedEvent($inMemoryCountRecord)); } - public function recordGauge(InMemoryGaugeRecord $inMemoryGaugeRecord): void { $this->dispatch(new GaugeRecordedEvent($inMemoryGaugeRecord)); @@ -50,7 +49,6 @@ public function recordSet(InMemorySetRecord $inMemorySetRecord): void $this->dispatch(new SetRecordedEvent($inMemorySetRecord)); } - public function recordHistogram(InMemoryHistogramRecord $inMemoryHistogramRecord): void { $this->dispatch(new HistogramRecordedEvent($inMemoryHistogramRecord)); @@ -61,7 +59,6 @@ public function recordDistribution(InMemoryDistributionRecord $inMemoryDistribut $this->dispatch(new DistributionRecordedEvent($inMemoryDistributionRecord)); } - protected function dispatch(StatRecordedEvent $statRecordedEvent): void { $this->dispatcher->dispatch($statRecordedEvent); From 6a5bd83e5f1a3265a6527b2ec0ef4f711ff82286 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Sat, 13 Jul 2024 11:12:50 -0400 Subject: [PATCH 4/8] move to contract --- src/Adapters/EventDispatchingStatsRecord.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Adapters/EventDispatchingStatsRecord.php b/src/Adapters/EventDispatchingStatsRecord.php index 49a9d6d..129d13f 100644 --- a/src/Adapters/EventDispatchingStatsRecord.php +++ b/src/Adapters/EventDispatchingStatsRecord.php @@ -16,7 +16,7 @@ use Cosmastech\StatsDClientAdapter\Adapters\InMemory\Models\InMemorySetRecord; use Cosmastech\StatsDClientAdapter\Adapters\InMemory\Models\InMemoryStatsRecord; use Cosmastech\StatsDClientAdapter\Adapters\InMemory\Models\InMemoryTimingRecord; -use Illuminate\Events\Dispatcher; +use Illuminate\Contracts\Events\Dispatcher; class EventDispatchingStatsRecord extends InMemoryStatsRecord { From 07fcc1706f9f947259dac1f353a61ec582991f65 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Sat, 13 Jul 2024 11:31:01 -0400 Subject: [PATCH 5/8] test timing --- .../EventDispatchingStatsRecordTest.php | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/Adapters/EventDispatchingStatsRecordTest.php diff --git a/tests/Adapters/EventDispatchingStatsRecordTest.php b/tests/Adapters/EventDispatchingStatsRecordTest.php new file mode 100644 index 0000000..13852d2 --- /dev/null +++ b/tests/Adapters/EventDispatchingStatsRecordTest.php @@ -0,0 +1,62 @@ +dispatcher = Event::fake(); + + $this->eventDispatchingStatsRecord = new EventDispatchingStatsRecord($this->dispatcher); + } + + #[Test] + public function time_dispatchesTimingRecordedEvent(): void + { + // Given + $inMemoryClient = new InMemoryClientAdapter([], $this->eventDispatchingStatsRecord); + + // And + $closure = fn() => ["hello" => "world"]; + + // When + $output = $inMemoryClient->time($closure, "my-timing-stat", 0.92, [ + "my-tag" => "my-value", + ]); + + // Then output should be returned from the client + self::assertEquals(["hello" => "world"], $output); + + // And an event should be dispatched + /** @var Collection> $eventsCollection */ + $eventsCollection = $this->dispatcher->dispatched(TimingRecordedEvent::class); + self::assertCount(1, $eventsCollection); + self::assertCount(1, $eventsCollection->first()); + + /** @var TimingRecordedEvent $event */ + $event = $eventsCollection->first()[0]; + + // And the record should have expected properties + $record = $event->record; + self::assertInstanceOf(InMemoryTimingRecord::class, $record); + self::assertEquals("my-timing-stat", $record->stat); + self::assertEquals(0.92, $record->sampleRate); + self::assertEquals(["my-tag" => "my-value"], $record->tags); + } +} From 1a7208dad3adbee7ebb30dab9e79a1166ba10ec3 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Sat, 13 Jul 2024 20:30:53 -0400 Subject: [PATCH 6/8] style --- tests/Adapters/EventDispatchingStatsRecordTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Adapters/EventDispatchingStatsRecordTest.php b/tests/Adapters/EventDispatchingStatsRecordTest.php index 13852d2..30fe1fd 100644 --- a/tests/Adapters/EventDispatchingStatsRecordTest.php +++ b/tests/Adapters/EventDispatchingStatsRecordTest.php @@ -33,7 +33,7 @@ public function time_dispatchesTimingRecordedEvent(): void $inMemoryClient = new InMemoryClientAdapter([], $this->eventDispatchingStatsRecord); // And - $closure = fn() => ["hello" => "world"]; + $closure = fn () => ["hello" => "world"]; // When $output = $inMemoryClient->time($closure, "my-timing-stat", 0.92, [ From 02deb0fe7c49883110cc35296c9c6fd6a15abc21 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Sat, 13 Jul 2024 20:38:15 -0400 Subject: [PATCH 7/8] custom adapter --- src/AdapterManager.php | 7 ++++--- src/Adapters/EventDispatchingAdapter.php | 9 +++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/Adapters/EventDispatchingAdapter.php diff --git a/src/AdapterManager.php b/src/AdapterManager.php index 97adda4..018bf0d 100644 --- a/src/AdapterManager.php +++ b/src/AdapterManager.php @@ -4,6 +4,7 @@ use Carbon\FactoryImmutable; use Carbon\WrapperClock; +use Cosmastech\LaravelStatsDAdapter\Adapters\EventDispatchingAdapter; use Cosmastech\LaravelStatsDAdapter\Adapters\EventDispatchingStatsRecord; use Cosmastech\StatsDClientAdapter\Adapters\Datadog\DatadogStatsDClientAdapter; use Cosmastech\StatsDClientAdapter\Adapters\InMemory\InMemoryClientAdapter; @@ -183,12 +184,12 @@ protected function createLeagueAdapter(array $config): LeagueStatsDClientAdapter /** * @param array $config - * @return InMemoryClientAdapter + * @return EventDispatchingAdapter * @throws BindingResolutionException */ - protected function createEventAdapter(array $config): InMemoryClientAdapter + protected function createEventAdapter(array $config): EventDispatchingAdapter { - return new InMemoryClientAdapter( + return new EventDispatchingAdapter( $this->getDefaultTags(), new EventDispatchingStatsRecord($this->app->make('events')), clock: $this->getClockImplementation() diff --git a/src/Adapters/EventDispatchingAdapter.php b/src/Adapters/EventDispatchingAdapter.php new file mode 100644 index 0000000..d274c27 --- /dev/null +++ b/src/Adapters/EventDispatchingAdapter.php @@ -0,0 +1,9 @@ + Date: Sat, 13 Jul 2024 20:52:38 -0400 Subject: [PATCH 8/8] bind record as a singleton --- src/StatsDAdapterServiceProvider.php | 10 +++++++++- tests/AdapterManagerTest.php | 16 ++++++++++++++++ tests/StatsDAdapterServiceProviderTest.php | 14 ++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/StatsDAdapterServiceProvider.php b/src/StatsDAdapterServiceProvider.php index 738eac9..ff73feb 100644 --- a/src/StatsDAdapterServiceProvider.php +++ b/src/StatsDAdapterServiceProvider.php @@ -2,6 +2,7 @@ namespace Cosmastech\LaravelStatsDAdapter; +use Cosmastech\LaravelStatsDAdapter\Adapters\EventDispatchingStatsRecord; use Cosmastech\StatsDClientAdapter\Adapters\StatsDClientAdapter; use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Support\DeferrableProvider; @@ -25,6 +26,13 @@ public function register(): void StatsDClientAdapter::class, fn (Application $app) => $app->make(AdapterManager::class)->instance() ); + + $this->app->singleton( + EventDispatchingStatsRecord::class, + function (Application $app): EventDispatchingStatsRecord { + return new EventDispatchingStatsRecord($app->make('events')); + } + ); } /** @@ -32,7 +40,7 @@ public function register(): void */ public function provides(): array { - return [AdapterManager::class, StatsDClientAdapter::class]; + return [AdapterManager::class, StatsDClientAdapter::class, EventDispatchingStatsRecord::class]; } protected function offerPublishing(): void diff --git a/tests/AdapterManagerTest.php b/tests/AdapterManagerTest.php index 1ba6a09..9043c27 100644 --- a/tests/AdapterManagerTest.php +++ b/tests/AdapterManagerTest.php @@ -2,6 +2,7 @@ namespace Cosmastech\LaravelStatsDAdapter\Tests; +use Cosmastech\LaravelStatsDAdapter\Adapters\EventDispatchingAdapter; use Cosmastech\StatsDClientAdapter\Adapters\Datadog\DatadogStatsDClientAdapter; use Cosmastech\StatsDClientAdapter\Adapters\InMemory\InMemoryClientAdapter; use Cosmastech\StatsDClientAdapter\Adapters\League\LeagueStatsDClientAdapter; @@ -144,4 +145,19 @@ public function setDefaultTags_passesToNewInstance(): void // Then self::assertEquals(["abc" => "123"], $adapterManager->instance("memory")->getDefaultTags()); } + + #[Test] + public function instance_event_returnsConfiguredEventDispatchingAdapter(): void + { + // Given + $adapterManager = $this->createAdapterManager(); + + // And events is configured + + // When + $eventDispatchingAdapter = $adapterManager->instance('event'); + + // Then + self::assertInstanceOf(EventDispatchingAdapter::class, $eventDispatchingAdapter); + } } diff --git a/tests/StatsDAdapterServiceProviderTest.php b/tests/StatsDAdapterServiceProviderTest.php index 2186a49..518c214 100644 --- a/tests/StatsDAdapterServiceProviderTest.php +++ b/tests/StatsDAdapterServiceProviderTest.php @@ -2,6 +2,7 @@ namespace Cosmastech\LaravelStatsDAdapter\Tests; +use Cosmastech\LaravelStatsDAdapter\Adapters\EventDispatchingStatsRecord; use Cosmastech\StatsDClientAdapter\Adapters\Datadog\DatadogStatsDClientAdapter; use Cosmastech\StatsDClientAdapter\Adapters\InMemory\InMemoryClientAdapter; use Cosmastech\StatsDClientAdapter\Adapters\StatsDClientAdapter; @@ -59,4 +60,17 @@ public function passesDefaultTagsToAdapterManager(): void // Then self::assertEqualsCanonicalizing($defaultTags, $clientAdapter->getDefaultTags()); } + + #[Test] + public function eventDispatchingStatsRecord_isSingleton(): void + { + // Given + $firstRecord = $this->app->make(EventDispatchingStatsRecord::class); + + // When + $secondRecord = $this->app->make(EventDispatchingStatsRecord::class); + + // Then + self::assertSame($firstRecord, $secondRecord); + } }