6 - Log structured success entry on PollFediverseAction with url count and duration

This commit is contained in:
myrmidex 2026-04-28 18:47:04 +02:00
parent a59c086da2
commit 9cecc47b8b
2 changed files with 54 additions and 18 deletions

View file

@ -5,6 +5,7 @@
namespace Lvl0\FediDiscover\Actions; namespace Lvl0\FediDiscover\Actions;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Lvl0\FediDiscover\Clients\FediverseClientFactory; use Lvl0\FediDiscover\Clients\FediverseClientFactory;
use Lvl0\FediDiscover\Events\UrlDiscovered; use Lvl0\FediDiscover\Events\UrlDiscovered;
@ -18,22 +19,26 @@ public function __construct(private FediverseClientFactory $factory) {}
public function execute(Instance $instance): void public function execute(Instance $instance): void
{ {
$start = microtime(true);
$client = $this->factory->for($instance); $client = $this->factory->for($instance);
$posts = $client->fetchPostsSince($instance, $instance->last_seen_id); $posts = $client->fetchPostsSince($instance, $instance->last_seen_id);
$posts->each(function (FediversePost $post) use ($instance) { $urlCount = $posts
try { ->map(function (FediversePost $post) use ($instance) {
$this->processLinks($post, $instance); try {
} catch (Throwable $e) { return $this->processLinks($post, $instance);
Log::warning('fedi-discover:processLinks failed', [ } catch (Throwable $e) {
'instance_id' => $instance->id, Log::warning('fedi-discover:processLinks failed', [
'instance_url' => $instance->url, 'instance_id' => $instance->id,
'post_url' => $post->selfUrl, 'instance_url' => $instance->url,
'exception' => $e::class, 'post_url' => $post->selfUrl,
'message' => $e->getMessage(), 'exception' => $e::class,
]); 'message' => $e->getMessage(),
} ]);
}); }
})
->sum();
if ($posts->isNotEmpty()) { if ($posts->isNotEmpty()) {
$instance->last_seen_id = $posts->first()->cursorId; $instance->last_seen_id = $posts->first()->cursorId;
@ -41,21 +46,27 @@ public function execute(Instance $instance): void
$instance->last_polled_at = now(); $instance->last_polled_at = now();
$instance->save(); $instance->save();
Log::info('fedi-discover:poll succeeded', [
'instance_id' => $instance->id,
'url_count' => $urlCount,
'duration_ms' => (int) round((microtime(true) - $start) * 1000),
]);
} }
private function processLinks(FediversePost $post, Instance $instance): void private function processLinks(FediversePost $post, Instance $instance): int
{ {
if ($post->body === null) { if ($post->body === null) {
return; return 0;
} }
$linksFound = preg_match_all('~https?://[^\s<>"\'()\[\]]+~', $post->body, $matches); $linksFound = preg_match_all('~https?://[^\s<>"\'()\[\]]+~', $post->body, $matches);
if ($linksFound === 0) { if ($linksFound === 0) {
return; return 0;
} }
collect($matches[0]) return collect($matches[0])
->map(fn (string $u) => rtrim($u, '.,;:!?')) ->map(fn (string $u) => rtrim($u, '.,;:!?'))
->filter(fn (string $u) => filter_var($u, FILTER_VALIDATE_URL) !== false) ->filter(fn (string $u) => filter_var($u, FILTER_VALIDATE_URL) !== false)
->filter(fn (string $u) => parse_url($u, PHP_URL_HOST) !== parse_url($instance->url, PHP_URL_HOST)) ->filter(fn (string $u) => parse_url($u, PHP_URL_HOST) !== parse_url($instance->url, PHP_URL_HOST))
@ -66,6 +77,7 @@ private function processLinks(FediversePost $post, Instance $instance): void
discoveredAt: CarbonImmutable::now(), discoveredAt: CarbonImmutable::now(),
postUrl: $post->selfUrl, postUrl: $post->selfUrl,
postBody: $post->body, postBody: $post->body,
)); ))
->count();
} }
} }

View file

@ -7,6 +7,7 @@
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Lvl0\FediDiscover\Actions\PollFediverseAction; use Lvl0\FediDiscover\Actions\PollFediverseAction;
use Lvl0\FediDiscover\Clients\FediverseClientFactory; use Lvl0\FediDiscover\Clients\FediverseClientFactory;
use Lvl0\FediDiscover\Clients\FediverseClientInterface; use Lvl0\FediDiscover\Clients\FediverseClientInterface;
@ -198,6 +199,29 @@ public function test_it_leaves_last_seen_id_unchanged_when_no_posts_are_returned
$this->assertSame('500', $instance->fresh()->last_seen_id); $this->assertSame('500', $instance->fresh()->last_seen_id);
} }
public function test_poll_logs_a_structured_success_entry_with_url_count_and_duration(): void
{
Log::spy();
Event::fake([UrlDiscovered::class]);
$instance = $this->makeInstance();
$this->pollInstance($instance, [
new FediversePost('1', 'https://mastodon.social/@alice/1', 'See https://example.com/one and https://other.example/two'),
new FediversePost('2', 'https://mastodon.social/@bob/2', 'Also https://example.com/three'),
]);
Log::shouldHaveReceived('info')
->once()
->withArgs(function (string $message, array $context) use ($instance): bool {
return $message === 'fedi-discover:poll succeeded'
&& $context['instance_id'] === $instance->id
&& $context['url_count'] === 3
&& isset($context['duration_ms'])
&& $context['duration_ms'] >= 0;
});
}
/** /**
* @param array<FediversePost> $posts * @param array<FediversePost> $posts
*/ */