Skip to content

Commit

Permalink
Add support for Sentry Developer Metrics (#1619)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Bouma <alex@bouma.me>
  • Loading branch information
cleptric and stayallive authored Dec 21, 2023
1 parent 2f6b413 commit c88988d
Show file tree
Hide file tree
Showing 24 changed files with 1,519 additions and 61 deletions.
10 changes: 10 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ parameters:
count: 1
path: src/Logger/DebugStdOutLogger.php

-
message: "#^Method Sentry\\\\Metrics\\\\Types\\\\AbstractType\\:\\:add\\(\\) has parameter \\$value with no type specified\\.$#"
count: 1
path: src/Metrics/Types/AbstractType.php

-
message: "#^Parameter \\#1 \\$level of method Monolog\\\\Handler\\\\AbstractHandler\\:\\:__construct\\(\\) expects 100\\|200\\|250\\|300\\|400\\|500\\|550\\|600\\|'ALERT'\\|'alert'\\|'CRITICAL'\\|'critical'\\|'DEBUG'\\|'debug'\\|'EMERGENCY'\\|'emergency'\\|'ERROR'\\|'error'\\|'INFO'\\|'info'\\|'NOTICE'\\|'notice'\\|'WARNING'\\|'warning'\\|Monolog\\\\Level, int\\|Monolog\\\\Level\\|string given\\.$#"
count: 1
Expand Down Expand Up @@ -230,6 +235,11 @@ parameters:
count: 1
path: src/Options.php

-
message: "#^Method Sentry\\\\Options\\:\\:shouldAttachMetricCodeLocations\\(\\) should return bool but returns mixed\\.$#"
count: 1
path: src/Options.php

-
message: "#^Method Sentry\\\\Options\\:\\:shouldAttachStacktrace\\(\\) should return bool but returns mixed\\.$#"
count: 1
Expand Down
29 changes: 29 additions & 0 deletions src/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Sentry\Context\OsContext;
use Sentry\Context\RuntimeContext;
use Sentry\Metrics\Types\AbstractType;
use Sentry\Profiling\Profile;
use Sentry\Tracing\Span;

Expand Down Expand Up @@ -55,6 +56,11 @@ final class Event
*/
private $checkIn;

/**
* @var array<string, AbstractType> The metrics data
*/
private $metrics = [];

/**
* @var string|null The name of the server (e.g. the host name)
*/
Expand Down Expand Up @@ -210,6 +216,11 @@ public static function createCheckIn(?EventId $eventId = null): self
return new self($eventId, EventType::checkIn());
}

public static function createMetrics(?EventId $eventId = null): self
{
return new self($eventId, EventType::metrics());
}

/**
* Gets the ID of this event.
*/
Expand Down Expand Up @@ -354,6 +365,24 @@ public function setCheckIn(?CheckIn $checkIn): self
return $this;
}

/**
* @return array<string, AbstractType>
*/
public function getMetrics(): array
{
return $this->metrics;
}

/**
* @param array<string, AbstractType> $metrics
*/
public function setMetrics(array $metrics): self
{
$this->metrics = $metrics;

return $this;
}

/**
* Gets the name of the server.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/EventType.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public static function checkIn(): self
return self::getInstance('check_in');
}

public static function metrics(): self
{
return self::getInstance('metrics');
}

public function __toString(): string
{
return $this->value;
Expand Down
32 changes: 27 additions & 5 deletions src/Integration/FrameContextifierIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Sentry\Event;
use Sentry\Frame;
use Sentry\SentrySdk;
use Sentry\Stacktrace;
use Sentry\State\Scope;
Expand Down Expand Up @@ -65,6 +66,13 @@ public function setupOnce(): void
}
}

foreach ($event->getMetrics() as $metric) {
if ($metric->hasCodeLocation()) {
$frame = $metric->getCodeLocation();
$integration->addContextToStacktraceFrame($maxContextLines, $frame);
}
}

return $event;
});
}
Expand All @@ -78,16 +86,30 @@ public function setupOnce(): void
private function addContextToStacktraceFrames(int $maxContextLines, Stacktrace $stacktrace): void
{
foreach ($stacktrace->getFrames() as $frame) {
if ($frame->isInternal() || $frame->getAbsoluteFilePath() === null) {
if ($frame->isInternal()) {
continue;
}

$sourceCodeExcerpt = $this->getSourceCodeExcerpt($maxContextLines, $frame->getAbsoluteFilePath(), $frame->getLine());
$this->addContextToStacktraceFrame($maxContextLines, $frame);
}
}

$frame->setPreContext($sourceCodeExcerpt['pre_context']);
$frame->setContextLine($sourceCodeExcerpt['context_line']);
$frame->setPostContext($sourceCodeExcerpt['post_context']);
/**
* Contextifies the given frame.
*
* @param int $maxContextLines The maximum number of lines of code to read
*/
private function addContextToStacktraceFrame(int $maxContextLines, Frame $frame): void
{
if ($frame->getAbsoluteFilePath() === null) {
return;
}

$sourceCodeExcerpt = $this->getSourceCodeExcerpt($maxContextLines, $frame->getAbsoluteFilePath(), $frame->getLine());

$frame->setPreContext($sourceCodeExcerpt['pre_context']);
$frame->setContextLine($sourceCodeExcerpt['context_line']);
$frame->setPostContext($sourceCodeExcerpt['post_context']);
}

/**
Expand Down
135 changes: 135 additions & 0 deletions src/Metrics/Metrics.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?php

declare(strict_types=1);

namespace Sentry\Metrics;

use Sentry\EventId;
use Sentry\Metrics\Types\CounterType;
use Sentry\Metrics\Types\DistributionType;
use Sentry\Metrics\Types\GaugeType;
use Sentry\Metrics\Types\SetType;

final class Metrics
{
/**
* @var self|null
*/
private static $instance;

/**
* @var MetricsAggregator
*/
private $aggregator;

private function __construct()
{
$this->aggregator = new MetricsAggregator();
}

public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new self();
}

return self::$instance;
}

/**
* @param int|float $value
* @param string[] $tags
*/
public function increment(
string $key,
$value,
?MetricsUnit $unit = null,
array $tags = [],
?int $timestamp = null,
int $stackLevel = 0
): void {
$this->aggregator->add(
CounterType::TYPE,
$key,
$value,
$unit,
$tags,
$timestamp,
$stackLevel
);
}

/**
* @param int|float $value
* @param string[] $tags
*/
public function distribution(
string $key,
$value,
?MetricsUnit $unit = null,
array $tags = [],
?int $timestamp = null,
int $stackLevel = 0
): void {
$this->aggregator->add(
DistributionType::TYPE,
$key,
$value,
$unit,
$tags,
$timestamp,
$stackLevel
);
}

/**
* @param int|float $value
* @param string[] $tags
*/
public function gauge(
string $key,
$value,
?MetricsUnit $unit = null,
array $tags = [],
?int $timestamp = null,
int $stackLevel = 0
): void {
$this->aggregator->add(
GaugeType::TYPE,
$key,
$value,
$unit,
$tags,
$timestamp,
$stackLevel
);
}

/**
* @param int|string $value
* @param string[] $tags
*/
public function set(
string $key,
$value,
?MetricsUnit $unit = null,
array $tags = [],
?int $timestamp = null,
int $stackLevel = 0
): void {
$this->aggregator->add(
SetType::TYPE,
$key,
$value,
$unit,
$tags,
$timestamp,
$stackLevel
);
}

public function flush(): ?EventId
{
return $this->aggregator->flush();
}
}
Loading

0 comments on commit c88988d

Please sign in to comment.