diff --git a/src/Drivers/AbstractDriver.php b/src/Drivers/AbstractDriver.php index 8522c42..ec2218e 100644 --- a/src/Drivers/AbstractDriver.php +++ b/src/Drivers/AbstractDriver.php @@ -103,6 +103,19 @@ public function formatted(): mixed return null; } + protected function flushMetricLogs(): void + { + foreach ($this->metrics as $metric) { + if ($metric->getLogMessage()) { + app('log')->log( + $metric->getLogLevel(), + $metric->getLogMessage(), + array_merge(['event' => $metric->getName()], $metric->getExtra()) + ); + } + } + } + abstract public function format(Metric $metric); abstract public function flush(): static; diff --git a/src/Drivers/CloudWatch.php b/src/Drivers/CloudWatch.php index 72c1d39..3d74e85 100644 --- a/src/Drivers/CloudWatch.php +++ b/src/Drivers/CloudWatch.php @@ -33,6 +33,8 @@ public function flush(): static return $this; } + $this->flushMetricLogs(); + $this->send($this->getMetrics()); $this->metrics = []; diff --git a/src/Drivers/InfluxDB.php b/src/Drivers/InfluxDB.php index 56fee95..0f1b16d 100644 --- a/src/Drivers/InfluxDB.php +++ b/src/Drivers/InfluxDB.php @@ -57,6 +57,8 @@ public function flush(): static return $this; } + $this->flushMetricLogs(); + $this->send($this->getMetrics()); $this->metrics = []; diff --git a/src/Drivers/LogDriver.php b/src/Drivers/LogDriver.php index b35c000..1f94fef 100644 --- a/src/Drivers/LogDriver.php +++ b/src/Drivers/LogDriver.php @@ -30,6 +30,8 @@ public function flush(): static return $this; } + $this->flushMetricLogs(); + $formatted = array_map([$this, 'format'], $this->getMetrics()); $this->logger->info("Metrics", $formatted); diff --git a/src/Drivers/PostHog.php b/src/Drivers/PostHog.php index 88c4a11..a21ecb3 100644 --- a/src/Drivers/PostHog.php +++ b/src/Drivers/PostHog.php @@ -12,24 +12,20 @@ public function __construct(protected string $distinctPrefix = '') { } - /** - * Note we are NOT enqueueing metrics on our own with PostHog. It queues internally - * and batches sends as it sees fit. Our best bet is to let PostHog do its thing. - * @throws Exception - */ - public function add(Metric $metric): static + public function flush(): static { - PostHogClient::capture($this->format($metric)); + if (empty($this->getMetrics())) { + return $this; + } - return $this; - } + $this->flushMetricLogs(); + + foreach ($this->getMetrics() as $metric) { + PostHogClient::capture($this->format($metric)); + } + + $this->metrics = []; - /** - * PostHog sends batches automatically on __destruct, this really isn't necessary. - * But we're including it in case you ever want to force send earlier on. - */ - public function flush(): static - { PostHogClient::flush(); return $this; diff --git a/src/Drivers/PrometheusDriver.php b/src/Drivers/PrometheusDriver.php index 3b57524..384e51d 100644 --- a/src/Drivers/PrometheusDriver.php +++ b/src/Drivers/PrometheusDriver.php @@ -48,6 +48,12 @@ public function format(Metric $metric): Collector public function flush(): static { + if (empty($this->metrics)) { + return $this; + } + + $this->flushMetricLogs(); + $this->metrics = []; $this->registry->wipeStorage(); return $this; diff --git a/src/Metric.php b/src/Metric.php index 48c56e0..6f4ef4c 100644 --- a/src/Metric.php +++ b/src/Metric.php @@ -49,6 +49,10 @@ class Metric protected ?string $description = null; + protected ?string $logMessage = null; + + protected string $logLevel = 'info'; + /** * Metric constructor. * @@ -149,7 +153,13 @@ public function addTag($key, $value): static public function getExtra(): array { - return value($this->extra); + $extra = value($this->extra); + + if ($this->logMessage) { + $extra['message'] = $this->logMessage; + } + + return $extra; } public function setExtra(array|\Closure $extra): static @@ -167,6 +177,24 @@ public function addExtra($key, $value): static return $this; } + public function withLog(string $message, string $level = 'info'): static + { + $this->logMessage = $message; + $this->logLevel = $level; + + return $this; + } + + public function getLogMessage(): ?string + { + return $this->logMessage; + } + + public function getLogLevel(): string + { + return $this->logLevel; + } + public function getTimestamp(): mixed { return $this->timestamp; diff --git a/tests/MetricTest.php b/tests/MetricTest.php index 82124d4..8aa849f 100644 --- a/tests/MetricTest.php +++ b/tests/MetricTest.php @@ -84,6 +84,57 @@ public function testAddExtraAfterClosureSet() $this->assertEquals(['foo' => 'bar', 'baz' => 'qux'], $metric->getExtra()); } + public function testWithLogStoresMessageAndLevel() + { + $metric = new Metric("my_metric", 1); + $metric->withLog("Something happened", "warning"); + + $this->assertEquals("Something happened", $metric->getLogMessage()); + $this->assertEquals("warning", $metric->getLogLevel()); + } + + public function testWithLogDefaultsToInfo() + { + $metric = new Metric("my_metric", 1); + $metric->withLog("Something happened"); + + $this->assertEquals("info", $metric->getLogLevel()); + } + + public function testWithLogAddsMessageToExtra() + { + $metric = new Metric("my_metric", 1); + $metric->setExtra(['key' => 'value']); + $metric->withLog("Something happened"); + + $extra = $metric->getExtra(); + + $this->assertEquals('value', $extra['key']); + $this->assertEquals('Something happened', $extra['message']); + } + + public function testWithLogFlushesLog() + { + $this->setupInfluxDB(); + + $log = Mockery::mock(\Psr\Log\LoggerInterface::class); + $log->shouldReceive('log') + ->once() + ->with('info', 'Something happened', Mockery::on(function ($context) { + return $context['event'] === 'my_metric' + && $context['key'] === 'value' + && $context['message'] === 'Something happened'; + })); + + app()->instance('log', $log); + + Metrics::create("my_metric") + ->withLog("Something happened") + ->setExtra(['key' => 'value']); + + Metrics::flush(); + } + public function testGivenTimestampIsntChanged() { $metric = new Metric('my_metric', 1);