Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for the Telemetry feature. #634

Merged
merged 4 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@
bootstrap="./tests/bootstrap.php"
colors="true"
cacheDirectory=".phpunit.cache"
defaultTestSuite="Rollbar Test Suite"
>
defaultTestSuite="Rollbar Test Suite">
<testsuites>
<testsuite name="Rollbar Test Suite">
<directory suffix=".php">./tests/</directory>
<exclude>./tests/Performance/</exclude>
<exclude>./tests/TestHelpers/</exclude>
<exclude>./tests/FakeDataBuilder.php</exclude>
<exclude>./tests/bootstrap.php</exclude>
<exclude>./tests/BaseRollbarTest.php</exclude>
<exclude>./tests/Performance/</exclude>
<exclude>./tests/TestHelpers/</exclude>
<exclude>./tests/FakeDataBuilder.php</exclude>
<exclude>./tests/bootstrap.php</exclude>
<exclude>./tests/BaseRollbarTest.php</exclude>
</testsuite>

<testsuite name="Rollbar Performance Test Suite">
<directory suffix=".php">./tests/Performance/</directory>
</testsuite>
<testsuite name="Rollbar Performance Test Suite">
<directory suffix=".php">./tests/Performance/</directory>
</testsuite>
</testsuites>

<coverage/>
Expand All @@ -27,10 +26,9 @@
<env name="ROLLBAR_TEST_TOKEN" value="ad865e76e7fb496fab096ac07b1dbabb"/>
</php>

<source>
<include>
<directory suffix=".php">./src</directory>
</include>
</source>

<source restrictDeprecations="true" restrictNotices="true" restrictWarnings="true">
<include>
<directory>src</directory>
</include>
</source>
</phpunit>
97 changes: 89 additions & 8 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Rollbar;

use InvalidArgumentException;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Handler\NoopHandler;
use Monolog\Logger;
Expand All @@ -12,6 +13,8 @@
use Rollbar\Senders\AgentSender;
use Rollbar\Senders\CurlSender;
use Rollbar\Senders\SenderInterface;
use Rollbar\Telemetry\Telemeter;
use Rollbar\Telemetry\TelemetryFilterInterface;
use Throwable;
use Rollbar\Senders\FluentSender;

Expand Down Expand Up @@ -60,6 +63,7 @@ class Config
'scrub_safelist',
'timeout',
'transmit',
'telemetry',
'custom_truncation',
'report_suppressed',
'use_error_reporting',
Expand Down Expand Up @@ -218,6 +222,13 @@ class Config
*/
private bool $raiseOnError = false;

/**
* @var null|array The telemetry config. If null, telemetry is disabled.
*
* @since 4.1.0
*/
private ?array $telemetry;

/**
* @var int The maximum number of items reported to Rollbar within one
* request.
Expand Down Expand Up @@ -303,6 +314,7 @@ protected function updateConfig(array $config): void
$this->setCheckIgnoreFunction($config);
$this->setSendMessageTrace($config);
$this->setRaiseOnError($config);
$this->setTelemetry($config);

if (isset($config['included_errno'])) {
$this->includedErrno = $config['included_errno'];
Expand Down Expand Up @@ -333,7 +345,7 @@ private function setAccessToken(array $config): void
if (isset($_ENV['ROLLBAR_ACCESS_TOKEN']) && !isset($config['access_token'])) {
$config['access_token'] = $_ENV['ROLLBAR_ACCESS_TOKEN'];
}

$this->utilities()->validateString(
$config['access_token'],
"config['access_token']",
Expand Down Expand Up @@ -443,7 +455,7 @@ private function setTransformer(array $config): void

private function setMinimumLevel(array $config): void
{
$this->minimumLevel = \Rollbar\Defaults::get()->minimumLevel();
$this->minimumLevel = Defaults::get()->minimumLevel();

$override = $config['minimum_level'] ?? null;
$override = array_key_exists('minimumLevel', $config) ? $config['minimumLevel'] : $override;
Expand All @@ -468,7 +480,7 @@ private function setReportSuppressed(array $config): void
}

if (!$this->reportSuppressed) {
$this->reportSuppressed = \Rollbar\Defaults::get()->reportSuppressed();
$this->reportSuppressed = Defaults::get()->reportSuppressed();
}
}

Expand Down Expand Up @@ -508,10 +520,24 @@ private function setRaiseOnError(array $config): void
if (array_key_exists('raise_on_error', $config)) {
$this->raiseOnError = $config['raise_on_error'];
} else {
$this->raiseOnError = \Rollbar\Defaults::get()->raiseOnError();
$this->raiseOnError = Defaults::get()->raiseOnError();
}
}

/**
* Sets and cleans the telemetry config.
*
* @param array $config The config array.
* @return void
*
* @since 4.1.0
*/
private function setTelemetry(array $config): void
{
$telemetry = key_exists('telemetry', $config) ? $config['telemetry']: true;
$this->telemetry = Defaults::get()->telemetry($telemetry);
}

private function setBatchSize(array $config): void
{
if (array_key_exists('batch_size', $config)) {
Expand Down Expand Up @@ -746,7 +772,7 @@ protected function setupWithOptions(
}

if (!$this->$keyName instanceof $expectedType) {
throw new \InvalidArgumentException(
throw new InvalidArgumentException(
"$keyName must be a $expectedType"
);
}
Expand Down Expand Up @@ -817,6 +843,61 @@ public function getRaiseOnError(): bool
return $this->raiseOnError;
}

/**
* Returns the telemetry instance or null if telemetry is disabled.
*
* @param Telemeter|null $telemeter An optional telemeter instance to scope the telemetry to. This allows us to
* keep the same telemeter instance when mutating the config. Otherwise, we would
* destroy the telemetry queue when mutating the config.
* @return Telemeter|null The telemetry instance or null if telemetry is disabled.
*
* @since 4.1.0
*/
public function getTelemetry(?Telemeter $telemeter): ?Telemeter
{
if (null === $this->telemetry) {
return null;
}
$config = $this->telemetry;
$config['filter'] = $this->initTelemetryFilter($config['filter']);
if (null === $telemeter) {
return new Telemeter(...$config);
}
$telemeter->scope(...$config);
return $telemeter;
}

/**
* Returns the telemetry filter instance or null if no filter is configured.
*
* @param string|null $filterClass The fully qualified class name of the telemetry filter class or null if no
* filter is configured.
* @return TelemetryFilterInterface|null
*
* @throws InvalidArgumentException if the configured filter class does not exist or does not implement
* {@see TelemetryFilterInterface}.
*
* @since 4.1.0
*/
private function initTelemetryFilter(?string $filterClass): ?TelemetryFilterInterface
{
if (null === $filterClass) {
return null;
}
if (!class_exists($filterClass)) {
throw new InvalidArgumentException(
"Telemetry filter class $filterClass does not exist"
);
}
$filter = new $filterClass($this->telemetry);
if (!$filter instanceof TelemetryFilterInterface) {
throw new InvalidArgumentException(
"Telemetry filter class $filterClass must implement TelemetryFilterInterface"
);
}
return $filter;
}

public function transform(
Payload $payload,
Level|string $level,
Expand Down Expand Up @@ -1058,9 +1139,9 @@ public function shouldSuppress(): bool
// > the value E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR |
// > E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE.
// https://www.php.net/manual/en/language.operators.errorcontrol.php
if (version_compare(PHP_VERSION, '8.0', 'ge') && $errorReporting === (
E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE
)) {
if ($errorReporting === (
E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE
)) {
return true;
}

Expand Down
57 changes: 34 additions & 23 deletions src/DataBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
use Rollbar\Payload\Server;
use Rollbar\Payload\Request;
use Rollbar\Payload\Data;
use Rollbar\Payload\TelemetryEvent;
use Rollbar\Payload\Trace;
use Rollbar\Payload\Frame;
use Rollbar\Payload\TraceChain;
use Rollbar\Payload\ExceptionInfo;
use Rollbar\Rollbar;
use Stringable;
use Throwable;

Expand Down Expand Up @@ -411,7 +411,7 @@ protected function getBody(Throwable|string|Stringable $toLog, array $context):
} else {
$content = $this->getMessage($toLog);
}
return new Body($content, $context);
return new Body($content, $context, $this->getTelemetry());
}

public function getErrorTrace(ErrorWrapper $error)
Expand Down Expand Up @@ -562,8 +562,8 @@ protected function getMessage($toLog)
return new Message(
(string)$toLog,
$this->sendMessageTrace ?
debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS) :
null
debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS) :
null
);
}

Expand Down Expand Up @@ -669,7 +669,19 @@ protected function getRequest()
}
return $request;
}


/**
* Returns the array of telemetry events to be sent with the payload or null if telemetry is not enabled.
*
* @return TelemetryEvent[]|null
*
* @since 4.1.0
*/
protected function getTelemetry(): ?array
{
return Rollbar::getTelemeter()?->copyEvents();
}

public function parseForwardedString($forwarded)
{
$result = array();
Expand Down Expand Up @@ -913,8 +925,7 @@ protected function getPerson()
try {
$personData = ($this->personFunc)();
} catch (\Exception $exception) {
Rollbar::scope(array('person_fn' => null))->
log(Level::ERROR, $exception);
Rollbar::scope(array('person_fn' => null))->log(Level::ERROR, $exception);
}
}

Expand Down Expand Up @@ -1247,27 +1258,27 @@ private function stripShutdownFrames($backTrace)
{
foreach ($backTrace as $index => $frame) {
extract($frame);

$fatalHandlerMethod = (isset($method)
&& $method === 'Rollbar\\Handlers\\FatalHandler::handle');
&& $method === 'Rollbar\\Handlers\\FatalHandler::handle');

$fatalHandlerClassAndFunction = (isset($class)
&& $class === 'Rollbar\\Handlers\\FatalHandler'
&& isset($function)
&& $function === 'handle');
&& $class === 'Rollbar\\Handlers\\FatalHandler'
&& isset($function)
&& $function === 'handle');

$errorHandlerMethod = (isset($method)
&& $method === 'Rollbar\\Handlers\\ErrorHandler::handle');
&& $method === 'Rollbar\\Handlers\\ErrorHandler::handle');

$errorHandlerClassAndFunction = (isset($class)
&& $class === 'Rollbar\\Handlers\\ErrorHandler'
&& isset($function)
&& $function === 'handle');
&& $class === 'Rollbar\\Handlers\\ErrorHandler'
&& isset($function)
&& $function === 'handle');

if ($fatalHandlerMethod ||
$fatalHandlerClassAndFunction ||
$errorHandlerMethod ||
$errorHandlerClassAndFunction) {
$fatalHandlerClassAndFunction ||
$errorHandlerMethod ||
$errorHandlerClassAndFunction) {
return array_slice($backTrace, $index+1);
}
}
Expand Down
36 changes: 35 additions & 1 deletion src/Defaults.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Monolog\Logger;
use Rollbar\Payload\Notifier;
use Psr\Log\LogLevel;
use Rollbar\Telemetry\Telemeter;
use Throwable;

class Defaults
Expand Down Expand Up @@ -328,12 +329,33 @@ public function minimumLevel($value = null)
{
return $value ?? $this->minimumLevel;
}

public function raiseOnError($value = null)
{
return $value ?? $this->raiseOnError;
}

/**
* Returns the telemetry configuration array or null if telemetry should be disabled.
*
* @param bool|array|null $value If true or null returns the default telemetry configuration. If false returns null.
*
* @return array|null The telemetry configuration.
*
* @since 4.1.0
*/
public function telemetry(bool|array|null $value = null): ?array
{
if (true === $value) {
return $this->telemetry;
}
if (is_array($value)) {
// Ensure that the telemetry array contains only the keys we expect and includes all the required keys.
return array_merge($this->telemetry, array_intersect_key($value, $this->telemetry));
}
return null;
}

private $psrLevels;
private $errorLevels;
private $autodetectBranch = false;
Expand Down Expand Up @@ -384,4 +406,16 @@ public function raiseOnError($value = null)
private $maxItems = 10;
private $minimumLevel = 0;
private $raiseOnError = false;

/**
* @var array $telemetry The default telemetry configuration.
*
* @since 4.1.0
*/
private array $telemetry = [
'maxTelemetryEvents' => Telemeter::MAX_EVENTS,
'filter' => null,
'includeItemsInTelemetry' => true,
'includeIgnoredItemsInTelemetry' => false,
];
}
Loading
Loading