Skip to content

Commit

Permalink
Refactor Profiler frame
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk committed Apr 14, 2024
1 parent 45a5b8a commit 2321f16
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 69 deletions.
27 changes: 19 additions & 8 deletions src/Proto/Frame/Profiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,35 @@
namespace Buggregator\Trap\Proto\Frame;

use Buggregator\Trap\Proto\Frame;
use Buggregator\Trap\Proto\Frame\Profiler\File;
use Buggregator\Trap\Proto\Frame\Profiler\Payload;
use Buggregator\Trap\ProtoType;
use Buggregator\Trap\Support\Json;
use DateTimeImmutable;

/**
* @internal
* @psalm-internal Buggregator
*/
abstract class Profiler extends Frame
final class Profiler extends Frame
{
public function __construct(
public readonly Frame\Profiler\Payload $payload,
DateTimeImmutable $time = new DateTimeImmutable(),
) {
parent::__construct(ProtoType::Profiler, $time);
}

public static function fromString(string $payload, DateTimeImmutable $time): static
{
$data = Json::decode($payload);

Check failure on line 27 in src/Proto/Frame/Profiler.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

MixedAssignment

src/Proto/Frame/Profiler.php:27:9: MixedAssignment: Unable to determine the type that $data is being assigned to (see https://psalm.dev/032)
return match (true) {
$data['type'] === File::PROFILE_FRAME_TYPE => File::fromArray($data, $time),
$data['type'] === Payload::PROFILE_FRAME_TYPE => Payload::fromArray($data, $time),
default => throw new \InvalidArgumentException('Unknown Profile frame type.'),
};

return new self(Frame\Profiler\Payload::fromArray($data), $time);

Check failure on line 29 in src/Proto/Frame/Profiler.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

MixedArgument

src/Proto/Frame/Profiler.php:29:59: MixedArgument: Argument 1 of Buggregator\Trap\Proto\Frame\Profiler\Payload::fromArray cannot be mixed, expecting array<array-key, mixed> (see https://psalm.dev/030)
}

/**
* @throws \JsonException
*/
public function __toString(): string
{
return Json::encode($this->payload->jsonSerialize() + ['']);
}
}
40 changes: 0 additions & 40 deletions src/Proto/Frame/Profiler/File.php

This file was deleted.

80 changes: 64 additions & 16 deletions src/Proto/Frame/Profiler/Payload.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,84 @@

namespace Buggregator\Trap\Proto\Frame\Profiler;

use Buggregator\Trap\Proto\Frame;
use Buggregator\Trap\ProtoType;
use Buggregator\Trap\Support\Json;
use DateTimeImmutable;
use Buggregator\Trap\Proto\Frame\Profiler\Type as PayloadType;
use Buggregator\Trap\Service\FilesObserver\FileInfo;

/**
* @psalm-type Metadata = array{
* date: int,
* hostname: non-empty-string,
* filename?: non-empty-string,
* ...
* }
* @psalm-type Calls = array{
* edges: array,
* peaks: array
* }
*
* @internal
* @psalm-internal Buggregator
*/
final class Payload extends Frame\Profiler
class Payload implements \JsonSerializable
{
public const PROFILE_FRAME_TYPE = 'payload';

public function __construct(
public array $payload,
DateTimeImmutable $time = new DateTimeImmutable(),
/**
* @param PayloadType $type
* @param Metadata $metadata
* @param \Closure(): Calls $callsProvider
*/
private function __construct(
public readonly PayloadType $type,
private array $metadata,
private \Closure $callsProvider,
) {
parent::__construct(ProtoType::Profiler, $time);
$this->metadata['type'] = $type->value;
}

public static function fromArray(array $data, ?Type $type = null): static
{
$metadata = $data;
unset($metadata['edges'], $metadata['peaks']);
return new static(

Check failure on line 44 in src/Proto/Frame/Profiler/Payload.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

UnsafeInstantiation

src/Proto/Frame/Profiler/Payload.php:44:16: UnsafeInstantiation: Cannot safely instantiate class Buggregator\Trap\Proto\Frame\Profiler\Payload with "new static" as its constructor might change in child classes (see https://psalm.dev/229)
$type ?? PayloadType::from($data['type']),

Check failure on line 45 in src/Proto/Frame/Profiler/Payload.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

MixedArgument

src/Proto/Frame/Profiler/Payload.php:45:40: MixedArgument: Argument 1 of Buggregator\Trap\Proto\Frame\Profiler\Type::from cannot be mixed, expecting int|string (see https://psalm.dev/030)
$metadata,

Check failure on line 46 in src/Proto/Frame/Profiler/Payload.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

ArgumentTypeCoercion

src/Proto/Frame/Profiler/Payload.php:46:13: ArgumentTypeCoercion: Argument 2 of Buggregator\Trap\Proto\Frame\Profiler\Payload::__construct expects array{date: int, filename?: non-empty-string, hostname: non-empty-string, ...<array-key, mixed>}, but parent type array<array-key, mixed> provided (see https://psalm.dev/193)
static fn(): array => $data,

Check failure on line 47 in src/Proto/Frame/Profiler/Payload.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

MixedArgumentTypeCoercion

src/Proto/Frame/Profiler/Payload.php:47:13: MixedArgumentTypeCoercion: Argument 3 of Buggregator\Trap\Proto\Frame\Profiler\Payload::__construct expects Closure():array{edges: array<array-key, mixed>, peaks: array<array-key, mixed>}, but parent type pure-Closure():array<array-key, mixed> provided (see https://psalm.dev/194)
);
}

public static function fromFile(FileInfo $fileInfo): static

Check failure on line 51 in src/Proto/Frame/Profiler/Payload.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

InvalidReturnType

src/Proto/Frame/Profiler/Payload.php:51:58: InvalidReturnType: Not all code paths of Buggregator\Trap\Proto\Frame\Profiler\Payload::fromFile end in a return statement, return type Buggregator\Trap\Proto\Frame\Profiler\Payload expected (see https://psalm.dev/011)
{
// todo
// $metadata = $data;
// unset($metadata['edges'], $metadata['peaks']);
// return new static(PayloadType::from($data['type']), $metadata, fn(): array => $data);
}

/**
* @throws \JsonException
* @return Calls
*/
public function __toString(): string
public function getCalls(): array
{
return Json::encode($this->payload);
return ($this->callsProvider)();
}

public static function fromArray(array $data, DateTimeImmutable $time): static
/**
* @return Metadata
*/
public function getMetadata(): array
{
return $this->metadata;
}

public function toArray(): array
{
return ['type' => $this->type->value] + $this->getCalls() + $this->getMetadata();
}

/**
* @return array{type: non-empty-string}&Calls&Metadata

Check failure on line 81 in src/Proto/Frame/Profiler/Payload.php

View workflow job for this annotation

GitHub Actions / Psalm Validation (PHP 8.2, OS ubuntu-latest)

MoreSpecificReturnType

src/Proto/Frame/Profiler/Payload.php:81:16: MoreSpecificReturnType: The declared return type 'array{date: int, edges: array<array-key, mixed>, filename?: non-empty-string, hostname: non-empty-string, peaks: array<array-key, mixed>, type: non-empty-string, ...<array-key, mixed>}' for Buggregator\Trap\Proto\Frame\Profiler\Payload::jsonSerialize is more specific than the inferred return type 'array<array-key, mixed>' (see https://psalm.dev/070)
*/
public function jsonSerialize(): array
{
return new self($data, $time);
return $this->toArray();
}
}
15 changes: 15 additions & 0 deletions src/Proto/Frame/Profiler/Type.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Buggregator\Trap\Proto\Frame\Profiler;

/**
* @internal
* @psalm-internal Buggregator
*/
enum Type: string
{
case XHProf = 'XHProf';
case XDebug = 'XDebug';
}
42 changes: 42 additions & 0 deletions src/Sender/Console/Renderer/Profiler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Buggregator\Trap\Sender\Console\Renderer;

use Buggregator\Trap\Proto\Frame;
use Buggregator\Trap\ProtoType;
use Buggregator\Trap\Sender\Console\Renderer;
use Buggregator\Trap\Sender\Console\Support\Common;
use DateTimeImmutable;
use Symfony\Component\Console\Output\OutputInterface;

/**
* @implements Renderer<Frame\Profiler>
*
* @internal
*/
final class Profiler implements Renderer
{
public function isSupport(Frame $frame): bool
{
return $frame->type === ProtoType::Profiler;
}

public function render(OutputInterface $output, Frame $frame): void
{
\assert($frame instanceof Frame\Profiler);

$subtitle = $frame->payload->type->value;
Common::renderHeader1($output, 'PROFILER', $subtitle);

$metadata = $frame->payload->getMetadata();
$data = [];
isset($metadata['date']) && \is_numeric($metadata['date'])
and $data['Time'] = new DateTimeImmutable('@' . $metadata['date']);
isset($metadata['hostname']) and $data['Hostname'] = $metadata['hostname'];
isset($metadata['filename']) and $data['File name'] = $metadata['filename'];

Common::renderMetadata($output, $data);
}
}
1 change: 1 addition & 0 deletions src/Sender/ConsoleSender.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public static function create(OutputInterface $output): self
$renderer->register(new Renderer\Monolog($templateRenderer));
$renderer->register(new Renderer\Smtp());
$renderer->register(new Renderer\Http());
$renderer->register(new Renderer\Profiler());
$renderer->register(new Renderer\Binary());
$renderer->register(new Renderer\Plain($templateRenderer));

Expand Down
2 changes: 1 addition & 1 deletion src/Sender/Frontend/FrameMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function map(Frame $frame): Event
Frame\Sentry\SentryStore::class => (new Mapper\SentryStore())->map($frame),
Frame\Sentry\SentryEnvelope::class => (new Mapper\SentryEnvelope())->map($frame),
Frame\Monolog::class => (new Mapper\Monolog())->map($frame),
Frame\Profiler\Payload::class => (new Mapper\Profiler())->map($frame),
Frame\Profiler::class => (new Mapper\Profiler())->map($frame),
default => throw new \InvalidArgumentException('Unknown frame type ' . $frame::class),
};
}
Expand Down
4 changes: 2 additions & 2 deletions src/Sender/Frontend/Mapper/Profiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
*/
final class Profiler
{
public function map(\Buggregator\Trap\Proto\Frame\Profiler\Payload $frame): Event
public function map(\Buggregator\Trap\Proto\Frame\Profiler $frame): Event
{
return new Event(
uuid: Uuid::generate(),
type: 'profiler',
payload: $frame->payload,
payload: $frame->payload->toArray(),
timestamp: (float)$frame->time->format('U.u'),
);
}
Expand Down
8 changes: 6 additions & 2 deletions src/Service/FilesObserver/Filter/XHProf.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ public function convert(FileInfo $file): \Traversable
$payload = $this->dataToPayload($data);
$payload['date'] = $file->mtime;
$payload['hostname'] = \explode('.', $file->getName(), 2)[0];
$payload['filename'] = $file->getName();

yield new ProfilerFrame\Payload(
$payload,
yield new ProfilerFrame(
ProfilerFrame\Payload::fromArray($payload, ProfilerFrame\Type::XHProf),
);
// yield new ProfilerFrame(
// ProfilerFrame\Payload::fromFile($file),
// );
} catch (\Throwable $e) {
// todo log
var_dump($e->getMessage());
Expand Down

0 comments on commit 2321f16

Please sign in to comment.