vendor/rollbar/rollbar/src/Config.php line 772

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Rollbar;
  3. use Monolog\Handler\ErrorLogHandler;
  4. use Monolog\Handler\NoopHandler;
  5. use Monolog\Logger;
  6. use Psr\Log\LoggerInterface;
  7. use Rollbar\Payload\Level;
  8. use Rollbar\Payload\Payload;
  9. use Rollbar\Payload\EncodedPayload;
  10. use Rollbar\Senders\AgentSender;
  11. use Rollbar\Senders\CurlSender;
  12. use Rollbar\Senders\SenderInterface;
  13. use Throwable;
  14. use Rollbar\Senders\FluentSender;
  15. class Config
  16. {
  17.     use UtilitiesTrait;
  18.     const VERBOSE_NONE     'none';
  19.     const VERBOSE_NONE_INT 1000;
  20.     private static array $options = array(
  21.         'access_token',
  22.         'agent_log_location',
  23.         'allow_exec',
  24.         'endpoint',
  25.         'base_api_url',
  26.         'autodetect_branch',
  27.         'branch',
  28.         'capture_error_stacktraces',
  29.         'check_ignore',
  30.         'code_version',
  31.         'custom',
  32.         'custom_data_method',
  33.         'enabled',
  34.         'environment',
  35.         'error_sample_rates',
  36.         'exception_sample_rates',
  37.         'fluent_host',
  38.         'fluent_port',
  39.         'fluent_tag',
  40.         'handler',
  41.         'host',
  42.         'include_error_code_context',
  43.         'include_exception_code_context',
  44.         'included_errno',
  45.         'log_payload',
  46.         'log_payload_logger',
  47.         'person',
  48.         'person_fn',
  49.         'capture_ip',
  50.         'capture_username',
  51.         'capture_email',
  52.         'root',
  53.         'scrubber',
  54.         'scrub_fields',
  55.         'scrub_safelist',
  56.         'timeout',
  57.         'transmit',
  58.         'custom_truncation',
  59.         'report_suppressed',
  60.         'use_error_reporting',
  61.         'proxy',
  62.         'send_message_trace',
  63.         'include_raw_request_body',
  64.         'local_vars_dump',
  65.         'max_nesting_depth',
  66.         'max_items',
  67.         'minimum_level',
  68.         'verbose',
  69.         'verbose_logger',
  70.         'raise_on_error',
  71.         'transformer',
  72.     );
  73.     private string $accessToken;
  74.     /**
  75.      * @var boolean $enabled If this is false then do absolutely nothing,
  76.      * try to be as close to the scenario where Rollbar did not exist at
  77.      * all in the code.
  78.      * Default: true
  79.      */
  80.     private bool $enabled true;
  81.     /**
  82.      * @var boolean $transmit If this is false then we do everything except
  83.      * make the post request at the end of the pipeline.
  84.      * Default: true
  85.      */
  86.     private bool $transmit;
  87.     /**
  88.      * @var boolean $logPayload If this is true then we output the payload to
  89.      * standard out or a configured logger right before transmitting.
  90.      * Default: false
  91.      */
  92.     private bool $logPayload;
  93.     /**
  94.      * @var LoggerInterface $logPayloadLogger Logger responsible for logging request
  95.      * payload and response dumps on. The messages logged can be controlled with
  96.      * `log_payload` config options.
  97.      * Default: \Monolog\Logger with \Monolog\Handler\ErrorLogHandler
  98.      */
  99.     private LoggerInterface $logPayloadLogger;
  100.     /**
  101.      * @var string $verbose If this is set to any of the \Psr\Log\LogLevel options
  102.      * then we output messages related to the processing of items that might be
  103.      * useful to someone trying to understand what Rollbar is doing. The logged
  104.      * messages are dependent on the level of verbosity. The supported options are
  105.      * all the log levels of \Psr\Log\LogLevel
  106.      * (https://github.com/php-fig/log/blob/master/Psr/Log/LogLevel.php) plus
  107.      * an additional Rollbar\Config::VERBOSE_NONE option which makes the SDK quiet
  108.      * (excluding `log_payload` option configured separetely).
  109.      * Essentially this option controls the level of verbosity of the default
  110.      * `verbose_logger`. If you override the default `verbose_logger`, you need
  111.      * to implement obeying the `verbose` config option yourself.
  112.      * Default: Rollbar\Config::VERBOSE_NONE
  113.      */
  114.     private string $verbose;
  115.     /**
  116.      * @var LoggerInterface $versbosity_logger The logger object used to log
  117.      * the internal messages of the SDK. The verbosity level of the default
  118.      * $verbosityLogger can be controlled with `verbose` config option.
  119.      * Default: \Rollbar\VerboseLogger
  120.      */
  121.     private LoggerInterface $verboseLogger;
  122.     /**
  123.      * @var DataBuilder
  124.      */
  125.     private $dataBuilder;
  126.     private $configArray;
  127.     /**
  128.      * @var TransformerInterface
  129.      */
  130.     private ?TransformerInterface $transformer null;
  131.     /**
  132.      * @var FilterInterface
  133.      */
  134.     private $filter;
  135.     /**
  136.      * @var int
  137.      */
  138.     private int $minimumLevel;
  139.     /**
  140.      * @var ResponseHandlerInterface
  141.      */
  142.     private $responseHandler;
  143.     /**
  144.      * @var \Rollbar\Senders\SenderInterface
  145.      */
  146.     private ?SenderInterface $sender null;
  147.     private $reportSuppressed;
  148.     /**
  149.      * @var Scrubber
  150.      */
  151.     private $scrubber;
  152.     private bool $batched false;
  153.     private int $batchSize 50;
  154.     private int $maxNestingDepth 10;
  155.     private array $custom = array();
  156.     /**
  157.      * @var callable with parameters $toLog, $contextDataMethodContext. The return
  158.      * value of the callable will be appended to the custom field of the item.
  159.      */
  160.     private $customDataMethod;
  161.     /**
  162.      * @var callable
  163.      */
  164.     private $checkIgnore;
  165.     private $errorSampleRates;
  166.     private $exceptionSampleRates;
  167.     private $mtRandmax;
  168.     private $includedErrno;
  169.     /**
  170.      * @var bool Sets whether to respect current {@see error_reporting()} level or not.
  171.      */
  172.     private bool $useErrorReporting false;
  173.     /**
  174.      * @var boolean Should debug_backtrace() data be sent with string messages
  175.      * sent through RollbarLogger::log().
  176.      */
  177.     private bool $sendMessageTrace false;
  178.     /**
  179.      * The fully qualified class name of a custom truncation strategy class or null if no custom class is specified.
  180.      * The class should implement {@see \Rollbar\Truncation\StrategyInterface}.
  181.      *
  182.      * @var string|null $customTruncation
  183.      *
  184.      * @since 1.6.0
  185.      * @since 4.0.0 Added string|null type, and defaults to null.
  186.      */
  187.     private ?string $customTruncation null;
  188.     /**
  189.      * @var boolean Should the SDK raise an exception after logging an error.
  190.      * This is useful in test and development enviroments.
  191.      * https://github.com/rollbar/rollbar-php/issues/448
  192.      */
  193.     private bool $raiseOnError false;
  194.     /**
  195.      * @var int The maximum number of items reported to Rollbar within one
  196.      * request.
  197.      */
  198.     private int $maxItems;
  199.     public function __construct(array $configArray)
  200.     {
  201.         $this->includedErrno Defaults::get()->includedErrno();
  202.         $this->updateConfig($configArray);
  203.         $this->errorSampleRates Defaults::get()->errorSampleRates();
  204.         if (isset($configArray['error_sample_rates'])) {
  205.             $this->errorSampleRates $configArray['error_sample_rates'];
  206.         }
  207.         $this->exceptionSampleRates Defaults::get()->exceptionSampleRates();
  208.         if (isset($configArray['exception_sample_rates'])) {
  209.             $this->exceptionSampleRates $configArray['exception_sample_rates'];
  210.         }
  211.         $levels = array(E_WARNINGE_NOTICEE_USER_ERRORE_USER_WARNING,
  212.             E_USER_NOTICEE_STRICTE_RECOVERABLE_ERROR);
  213.         // PHP 5.3.0
  214.         if (defined('E_DEPRECATED')) {
  215.             $levels array_merge($levels, array(E_DEPRECATEDE_USER_DEPRECATED));
  216.         }
  217.         $curr 1;
  218.         for ($i 0$num count($levels); $i $num$i++) {
  219.             $level $levels[$i];
  220.             if (!isset($this->errorSampleRates[$level])) {
  221.                 $this->errorSampleRates[$level] = $curr;
  222.             }
  223.         }
  224.         $this->mtRandmax mt_getrandmax();
  225.     }
  226.     public static function listOptions(): array
  227.     {
  228.         return self::$options;
  229.     }
  230.     public function configure(array $config): void
  231.     {
  232.         $this->updateConfig($this->extend($config));
  233.     }
  234.     public function extend(array $config): array
  235.     {
  236.         return array_replace_recursive(array(), $this->configArray$config);
  237.     }
  238.     public function getConfigArray(): array
  239.     {
  240.         return $this->configArray;
  241.     }
  242.     protected function updateConfig(array $config): void
  243.     {
  244.         $this->configArray $config;
  245.         $this->setEnabled($config);
  246.         $this->setTransmit($config);
  247.         $this->setLogPayload($config);
  248.         $this->setLogPayloadLogger($config);
  249.         $this->setVerbose($config);
  250.         $this->setVerboseLogger($config);
  251.         // The sender must be set before the access token, so we know if it is required.
  252.         $this->setSender($config);
  253.         $this->setAccessToken($config);
  254.         $this->setDataBuilder($config);
  255.         $this->setTransformer($config);
  256.         $this->setMinimumLevel($config);
  257.         $this->setReportSuppressed($config);
  258.         $this->setFilters($config);
  259.         $this->setScrubber($config);
  260.         $this->setBatched($config);
  261.         $this->setBatchSize($config);
  262.         $this->setMaxNestingDepth($config);
  263.         $this->setCustom($config);
  264.         $this->setResponseHandler($config);
  265.         $this->setCheckIgnoreFunction($config);
  266.         $this->setSendMessageTrace($config);
  267.         $this->setRaiseOnError($config);
  268.         if (isset($config['included_errno'])) {
  269.             $this->includedErrno $config['included_errno'];
  270.         }
  271.         $this->useErrorReporting Defaults::get()->useErrorReporting();
  272.         if (isset($config['use_error_reporting'])) {
  273.             $this->useErrorReporting $config['use_error_reporting'];
  274.         }
  275.         $this->maxItems Defaults::get()->maxItems();
  276.         if (isset($config['max_items'])) {
  277.             $this->maxItems $config['max_items'];
  278.         }
  279.         if (isset($config['custom_truncation'])) {
  280.             $this->customTruncation $config['custom_truncation'];
  281.         }
  282.         $this->customDataMethod Defaults::get()->customDataMethod();
  283.         if (isset($config['custom_data_method'])) {
  284.             $this->customDataMethod $config['custom_data_method'];
  285.         }
  286.     }
  287.     private function setAccessToken(array $config): void
  288.     {
  289.         if (isset($_ENV['ROLLBAR_ACCESS_TOKEN']) && !isset($config['access_token'])) {
  290.             $config['access_token'] = $_ENV['ROLLBAR_ACCESS_TOKEN'];
  291.         }
  292.         
  293.         $this->utilities()->validateString(
  294.             $config['access_token'],
  295.             "config['access_token']",
  296.             32,
  297.             !$this->sender->requireAccessToken(),
  298.         );
  299.         $this->accessToken $config['access_token'] ?? '';
  300.     }
  301.     private function setEnabled(array $config): void
  302.     {
  303.         if (array_key_exists('enabled'$config) && $config['enabled'] === false) {
  304.             $this->disable();
  305.         } else {
  306.             if (Defaults::get()->enabled() === false) {
  307.                 $this->disable();
  308.             } else {
  309.                 $this->enable();
  310.             }
  311.         }
  312.     }
  313.     private function setTransmit(array $config): void
  314.     {
  315.         $this->transmit $config['transmit'] ?? Defaults::get()->transmit();
  316.     }
  317.     private function setLogPayload(array $config): void
  318.     {
  319.         $this->logPayload $config['log_payload'] ?? Defaults::get()->logPayload();
  320.     }
  321.     private function setLogPayloadLogger(array $config): void
  322.     {
  323.         $this->logPayloadLogger $config['log_payload_logger'] ??
  324.             new Logger('rollbar.payload', array(new ErrorLogHandler()));
  325.         if (!($this->logPayloadLogger instanceof LoggerInterface)) {
  326.             throw new \Exception('Log Payload Logger must implement \Psr\Log\LoggerInterface');
  327.         }
  328.     }
  329.     private function setVerbose(array $config): void
  330.     {
  331.         $this->verbose $config['verbose'] ?? Defaults::get()->verbose();
  332.     }
  333.     private function setVerboseLogger(array $config): void
  334.     {
  335.         if (isset($config['verbose_logger'])) {
  336.             $this->verboseLogger $config['verbose_logger'];
  337.         } else {
  338.             $verboseLevel $this->verboseInteger();
  339.             // The verboseLogger must be an instance of LoggerInterface. Setting
  340.             // it to null would require every log call to check if it is null,
  341.             // so we set it to a NoopHandler instead. The NoopHandler does what
  342.             // you would expect and does nothing.
  343.             //
  344.             // Additionally, since Monolog v3 all log levels are defined in an
  345.             // enum. This means that using a custom log level will throw an
  346.             // exception. To avoid this we only set the level if it is not our
  347.             // "custom" verbose level.
  348.             //
  349.             // Using a built-in level would cause the verbose logger to log
  350.             // messages that are currently silent if the verbose log leve is set
  351.             // to "none".
  352.             if ($verboseLevel === self::VERBOSE_NONE_INT) {
  353.                 $handler = new NoopHandler();
  354.             } else {
  355.                 $handler = new ErrorLogHandler();
  356.                 $handler->setLevel($verboseLevel);
  357.             }
  358.             $this->verboseLogger = new Logger('rollbar.verbose', array($handler));
  359.         }
  360.         if (!($this->verboseLogger instanceof LoggerInterface)) {
  361.             throw new \Exception('Verbose logger must implement \Psr\Log\LoggerInterface');
  362.         }
  363.     }
  364.     public function enable(): void
  365.     {
  366.         $this->enabled true;
  367.     }
  368.     public function disable(): void
  369.     {
  370.         $this->enabled false;
  371.     }
  372.     private function setDataBuilder(array $config): void
  373.     {
  374.         if (!isset($config['utilities'])) {
  375.             $config['utilities'] = $this->utilities();
  376.         }
  377.         $exp DataBuilderInterface::class;
  378.         $def DataBuilder::class;
  379.         $this->setupWithOptions($config"dataBuilder"$exp$deftrue);
  380.     }
  381.     private function setTransformer(array $config): void
  382.     {
  383.         $expected TransformerInterface::class;
  384.         $this->setupWithOptions($config"transformer"$expected);
  385.     }
  386.     private function setMinimumLevel(array $config): void
  387.     {
  388.         $this->minimumLevel \Rollbar\Defaults::get()->minimumLevel();
  389.         $override $config['minimum_level'] ?? null;
  390.         $override array_key_exists('minimumLevel'$config) ? $config['minimumLevel'] : $override;
  391.         if ($override instanceof Level) {
  392.             $this->minimumLevel $override->toInt();
  393.         } elseif (is_string($override)) {
  394.             $level LevelFactory::fromName($override);
  395.             if ($level !== null) {
  396.                 $this->minimumLevel $level->toInt();
  397.             }
  398.         } elseif (is_int($override)) {
  399.             $this->minimumLevel $override;
  400.         }
  401.     }
  402.     private function setReportSuppressed(array $config): void
  403.     {
  404.         $this->reportSuppressed = isset($config['reportSuppressed']) && $config['reportSuppressed'];
  405.         if (!$this->reportSuppressed) {
  406.             $this->reportSuppressed = isset($config['report_suppressed']) && $config['report_suppressed'];
  407.         }
  408.         if (!$this->reportSuppressed) {
  409.             $this->reportSuppressed \Rollbar\Defaults::get()->reportSuppressed();
  410.         }
  411.     }
  412.     private function setFilters(array $config): void
  413.     {
  414.         $this->setupWithOptions($config"filter"FilterInterface::class);
  415.     }
  416.     private function setSender(array $config): void
  417.     {
  418.         $expected SenderInterface::class;
  419.         $default CurlSender::class;
  420.         $this->setTransportOptions($config);
  421.         $default $this->setAgentSenderOptions($config$default);
  422.         $default $this->setFluentSenderOptions($config$default);
  423.         $this->setupWithOptions($config"sender"$expected$default);
  424.     }
  425.     private function setScrubber(array $config): void
  426.     {
  427.         $exp ScrubberInterface::class;
  428.         $def Scrubber::class;
  429.         $this->setupWithOptions($config"scrubber"$exp$deftrue);
  430.     }
  431.     private function setBatched(array $config): void
  432.     {
  433.         if (array_key_exists('batched'$config)) {
  434.             $this->batched $config['batched'];
  435.         }
  436.     }
  437.     private function setRaiseOnError(array $config): void
  438.     {
  439.         if (array_key_exists('raise_on_error'$config)) {
  440.             $this->raiseOnError $config['raise_on_error'];
  441.         } else {
  442.             $this->raiseOnError \Rollbar\Defaults::get()->raiseOnError();
  443.         }
  444.     }
  445.     private function setBatchSize(array $config): void
  446.     {
  447.         if (array_key_exists('batch_size'$config)) {
  448.             $this->batchSize $config['batch_size'];
  449.         }
  450.     }
  451.     private function setMaxNestingDepth(array $config): void
  452.     {
  453.         if (array_key_exists('max_nesting_depth'$config)) {
  454.             $this->maxNestingDepth $config['max_nesting_depth'];
  455.         }
  456.     }
  457.     public function setCustom(array $config): void
  458.     {
  459.         $this->dataBuilder->setCustom($config);
  460.     }
  461.     public function addCustom($key$data)
  462.     {
  463.         $this->dataBuilder->addCustom($key$data);
  464.     }
  465.     public function removeCustom($key)
  466.     {
  467.         $this->dataBuilder->removeCustom($key);
  468.     }
  469.     public function transmitting(): bool
  470.     {
  471.         return $this->transmit;
  472.     }
  473.     public function loggingPayload()
  474.     {
  475.         return $this->logPayload;
  476.     }
  477.     public function verbose(): string
  478.     {
  479.         return $this->verbose;
  480.     }
  481.     public function verboseInteger(): int
  482.     {
  483.         if ($this->verbose == self::VERBOSE_NONE) {
  484.             return self::VERBOSE_NONE_INT;
  485.         }
  486.         /**
  487.          * @psalm-suppress UndefinedClass
  488.          * @psalm-suppress UndefinedDocblockClass
  489.          * @var int|\Monolog\Level $level Monolog v2 returns an integer, v3 returns a \Monolog\Level enum.
  490.          */
  491.         $level Logger::toMonologLevel($this->verbose);
  492.         /**
  493.          * @psalm-suppress UndefinedClass
  494.          */
  495.         if (is_a($level'\Monolog\Level')) {
  496.             return $level->value;
  497.         }
  498.         return $level;
  499.     }
  500.     public function getCustom()
  501.     {
  502.         return $this->dataBuilder->getCustom();
  503.     }
  504.     /**
  505.      * Sets the custom truncation strategy class for payloads.
  506.      *
  507.      * @param string|null $type The fully qualified class name of the custom payload truncation strategy. The class
  508.      *                          must implement {@see \Rollbar\Truncation\StrategyInterface}. If null is given any custom
  509.      *                          strategy will be removed.
  510.      *
  511.      * @return void
  512.      */
  513.     public function setCustomTruncation(?string $type): void
  514.     {
  515.         $this->customTruncation $type;
  516.     }
  517.     /**
  518.      * Returns the fully qualified class name of the custom payload truncation strategy.
  519.      *
  520.      * @return string|null Will return null if a custom truncation strategy was not defined.
  521.      *
  522.      * @since 1.6.0
  523.      * @since 4.0.0 Added may return null.
  524.      */
  525.     public function getCustomTruncation(): ?string
  526.     {
  527.         return $this->customTruncation;
  528.     }
  529.     private function setTransportOptions(array &$config): void
  530.     {
  531.         if (array_key_exists('base_api_url'$config)) {
  532.             $config['senderOptions']['endpoint'] = $config['base_api_url'] . 'item/';
  533.         }
  534.         if (array_key_exists('endpoint'$config)) {
  535.             $config['senderOptions']['endpoint'] = $config['endpoint'] . 'item/';
  536.         }
  537.         if (array_key_exists('timeout'$config)) {
  538.             $config['senderOptions']['timeout'] = $config['timeout'];
  539.         }
  540.         if (array_key_exists('proxy'$config)) {
  541.             $config['senderOptions']['proxy'] = $config['proxy'];
  542.         }
  543.         if (array_key_exists('ca_cert_path'$config)) {
  544.             $config['senderOptions']['ca_cert_path'] = $config['ca_cert_path'];
  545.         }
  546.     }
  547.     private function setAgentSenderOptions(array &$configmixed $default): mixed
  548.     {
  549.         if (!array_key_exists('handler'$config) || $config['handler'] != 'agent') {
  550.             return $default;
  551.         }
  552.         $default AgentSender::class;
  553.         if (array_key_exists('agent_log_location'$config)) {
  554.             $config['senderOptions'] = array(
  555.                 'agentLogLocation' => $config['agent_log_location']
  556.             );
  557.         }
  558.         return $default;
  559.     }
  560.     private function setFluentSenderOptions(array &$configmixed $default): mixed
  561.     {
  562.         if (!isset($config['handler']) || $config['handler'] != 'fluent') {
  563.             return $default;
  564.         }
  565.         $default FluentSender::class;
  566.         if (isset($config['fluent_host'])) {
  567.             $config['senderOptions']['fluentHost'] = $config['fluent_host'];
  568.         }
  569.         if (isset($config['fluent_port'])) {
  570.             $config['senderOptions']['fluentPort'] = $config['fluent_port'];
  571.         }
  572.         if (isset($config['fluent_tag'])) {
  573.             $config['senderOptions']['fluentTag'] = $config['fluent_tag'];
  574.         }
  575.         return $default;
  576.     }
  577.     private function setResponseHandler(array $config): void
  578.     {
  579.         $this->setupWithOptions($config"responseHandler"ResponseHandlerInterface::class);
  580.     }
  581.     private function setCheckIgnoreFunction(array $config): void
  582.     {
  583.         // Remain backwards compatible
  584.         if (isset($config['checkIgnore'])) {
  585.             $this->checkIgnore $config['checkIgnore'];
  586.         }
  587.         if (isset($config['check_ignore'])) {
  588.             $this->checkIgnore $config['check_ignore'];
  589.         }
  590.     }
  591.     private function setSendMessageTrace(array $config): void
  592.     {
  593.         if (!isset($config['send_message_trace'])) {
  594.             return;
  595.         }
  596.         $this->sendMessageTrace $config['send_message_trace'];
  597.     }
  598.     /**
  599.      * Allows setting up configuration options that might be specified by class
  600.      * name. Any interface used with `setupWithOptions` should be constructed
  601.      * with a single parameter: an associative array with the config options.
  602.      * It is assumed that it will be in the configuration as a sibling to the
  603.      * key the class is named in. The options should have the same key as the
  604.      * classname, but with 'Options' appended. E.g:
  605.      * ```array(
  606.      *   "sender" => "MySender",
  607.      *   "senderOptions" => array(
  608.      *     "speed" => 11,
  609.      *     "protocol" => "First Contact"
  610.      *   )
  611.      * );```
  612.      * Will be initialized as if you'd used:
  613.      * `new MySender(array("speed"=>11,"protocol"=>"First Contact"));`
  614.      * You can also just pass an instance in directly. (In which case options
  615.      * are ignored)
  616.      * @param array $config
  617.      * @param string $keyName
  618.      * @param string $expectedType
  619.      * @param ?string $defaultClass
  620.      * @param bool $passWholeConfig
  621.      */
  622.     protected function setupWithOptions(
  623.         array $config,
  624.         string $keyName,
  625.         string $expectedType,
  626.         ?string $defaultClass null,
  627.         bool $passWholeConfig false
  628.     ): void {
  629.         $class $config[$keyName] ?? null;
  630.         if (is_null($defaultClass) && is_null($class)) {
  631.             return;
  632.         }
  633.         if (is_null($class)) {
  634.             $class $defaultClass;
  635.         }
  636.         if (is_string($class)) {
  637.             if ($passWholeConfig) {
  638.                 $options $config;
  639.             } else {
  640.                 $options $config[$keyName "Options"] ?? array();
  641.             }
  642.             $this->$keyName = new $class($options);
  643.         } else {
  644.             $this->$keyName $class;
  645.         }
  646.         if (!$this->$keyName instanceof $expectedType) {
  647.             throw new \InvalidArgumentException(
  648.                 "$keyName must be a $expectedType"
  649.             );
  650.         }
  651.     }
  652.     /**
  653.      * Returns the logger responsible for logging request payload and response dumps, if enabled.
  654.      *
  655.      * @return LoggerInterface
  656.      */
  657.     public function logPayloadLogger(): LoggerInterface
  658.     {
  659.         return $this->logPayloadLogger;
  660.     }
  661.     public function verboseLogger(): LoggerInterface
  662.     {
  663.         return $this->verboseLogger;
  664.     }
  665.     public function getRollbarData($level$toLog$context)
  666.     {
  667.         return $this->dataBuilder->makeData($level$toLog$context);
  668.     }
  669.     public function getDataBuilder()
  670.     {
  671.         return $this->dataBuilder;
  672.     }
  673.     public function getSender()
  674.     {
  675.         return $this->sender;
  676.     }
  677.     public function getScrubber()
  678.     {
  679.         return $this->scrubber;
  680.     }
  681.     public function getBatched(): bool
  682.     {
  683.         return $this->batched;
  684.     }
  685.     public function getBatchSize(): int
  686.     {
  687.         return $this->batchSize;
  688.     }
  689.     public function getMaxNestingDepth(): int
  690.     {
  691.         return $this->maxNestingDepth;
  692.     }
  693.     public function getMaxItems(): int
  694.     {
  695.         return $this->maxItems;
  696.     }
  697.     public function getMinimumLevel(): int
  698.     {
  699.         return $this->minimumLevel;
  700.     }
  701.     public function getRaiseOnError(): bool
  702.     {
  703.         return $this->raiseOnError;
  704.     }
  705.     public function transform(
  706.         Payload $payload,
  707.         Level|string $level,
  708.         mixed $toLog,
  709.         array $context = array ()
  710.     ): Payload {
  711.         if (count($this->custom) > 0) {
  712.             $this->verboseLogger()->debug("Adding custom data to the payload.");
  713.             $data $payload->getData();
  714.             $custom $data->getCustom();
  715.             $custom array_merge(array(), $this->custom, (array)$custom);
  716.             $data->setCustom($custom);
  717.             $payload->setData($data);
  718.         }
  719.         if (is_null($this->transformer)) {
  720.             return $payload;
  721.         }
  722.         $this->verboseLogger()->debug("Applying transformer " get_class($this->transformer) . " to the payload.");
  723.         return $this->transformer->transform($payload$level$toLog$context);
  724.     }
  725.     public function getAccessToken(): string
  726.     {
  727.         return $this->accessToken;
  728.     }
  729.     public function enabled(): bool
  730.     {
  731.         return $this->enabled === true;
  732.     }
  733.     public function disabled(): bool
  734.     {
  735.         return !$this->enabled();
  736.     }
  737.     public function getSendMessageTrace()
  738.     {
  739.         return $this->sendMessageTrace;
  740.     }
  741.     public function checkIgnored(Payload $payload$toLogbool $isUncaught)
  742.     {
  743.         if (isset($this->checkIgnore)) {
  744.             try {
  745.                 $ok = ($this->checkIgnore)($isUncaught$toLog$payload);
  746.                 if ($ok) {
  747.                     $this->verboseLogger()->info('Occurrence ignored due to custom check_ignore logic');
  748.                     return true;
  749.                 }
  750.             } catch (Throwable $exception) {
  751.                 $this->verboseLogger()->error(
  752.                     'Exception occurred in the custom checkIgnore logic:' $exception->getMessage()
  753.                 );
  754.                 $this->checkIgnore null;
  755.             }
  756.         }
  757.         if ($this->payloadLevelTooLow($payload)) {
  758.             $this->verboseLogger()->debug("Occurrence's level is too low");
  759.             return true;
  760.         }
  761.         if (!is_null($this->filter)) {
  762.             $filter $this->filter->shouldSend($payload$isUncaught);
  763.             $this->verboseLogger()->debug("Custom filter result: " var_export($filtertrue));
  764.             return $filter;
  765.         }
  766.         return false;
  767.     }
  768.     public function internalCheckIgnored(string $levelmixed $toLog): bool
  769.     {
  770.         if ($this->shouldSuppress()) {
  771.             $this->verboseLogger()->debug('Ignoring (error reporting has been disabled in PHP config)');
  772.             return true;
  773.         }
  774.         if ($this->levelTooLow(LevelFactory::fromName($level))) {
  775.             $this->verboseLogger()->debug("Occurrence's level is too low");
  776.             return true;
  777.         }
  778.         if ($toLog instanceof ErrorWrapper) {
  779.             return $this->shouldIgnoreErrorWrapper($toLog);
  780.         }
  781.         if ($toLog instanceof \Exception) {
  782.             return $this->shouldIgnoreException($toLog);
  783.         }
  784.         return false;
  785.     }
  786.     /**
  787.      * Check if the error should be ignored due to `includedErrno` config, `useErrorReporting` config or
  788.      * `errorSampleRates` config.
  789.      *
  790.      * @param int $errno The PHP error level bitmask.
  791.      *
  792.      * @return bool
  793.      */
  794.     public function shouldIgnoreError(int $errno): bool
  795.     {
  796.         if ($this->useErrorReporting && ($errno error_reporting()) === 0) {
  797.             // ignore due to error_reporting level
  798.             $this->verboseLogger()->debug("Ignore (error below allowed error_reporting level)");
  799.             return true;
  800.         }
  801.         if ($this->includedErrno != -&& ($errno $this->includedErrno) != $errno) {
  802.             // ignore
  803.             $this->verboseLogger()->debug("Ignore due to included_errno level");
  804.             return true;
  805.         }
  806.         if (isset($this->errorSampleRates[$errno])) {
  807.             // get a float in the range [0, 1)
  808.             // mt_rand() is inclusive, so add 1 to mt_randmax
  809.             $float_rand mt_rand() / ($this->mtRandmax 1);
  810.             if ($float_rand $this->errorSampleRates[$errno]) {
  811.                 // skip
  812.                 $this->verboseLogger()->debug("Skip due to error sample rating");
  813.                 return true;
  814.             }
  815.         }
  816.         return false;
  817.     }
  818.     /**
  819.      * Check if the error should be ignored due to `included_errno` config,
  820.      * `use_error_reporting` config or `error_sample_rates` config.
  821.      *
  822.      * @param \Rollbar\ErrorWrapper $toLog
  823.      *
  824.      * @return bool
  825.      */
  826.     protected function shouldIgnoreErrorWrapper(ErrorWrapper $toLog): bool
  827.     {
  828.         return $this->shouldIgnoreError($toLog->errorLevel);
  829.     }
  830.     /**
  831.      * Check if the exception should be ignored due to configured exception
  832.      * sample rates.
  833.      *
  834.      * @param \Exception $toLog
  835.      *
  836.      * @return bool
  837.      */
  838.     public function shouldIgnoreException(\Exception $toLog): bool
  839.     {
  840.         // get a float in the range [0, 1)
  841.         // mt_rand() is inclusive, so add 1 to mt_randmax
  842.         $floatRand mt_rand() / ($this->mtRandmax 1);
  843.         if ($floatRand $this->exceptionSampleRate($toLog)) {
  844.             // skip
  845.             $this->verboseLogger()->debug("Skip exception due to exception sample rating");
  846.             return true;
  847.         }
  848.         return false;
  849.     }
  850.     /**
  851.      * Calculate what's the chance of logging this exception according to
  852.      * exception sampling.
  853.      *
  854.      * @param \Exception $toLog
  855.      *
  856.      * @return float
  857.      */
  858.     public function exceptionSampleRate(\Exception $toLog): float
  859.     {
  860.         $sampleRate 1.0;
  861.         if (count($this->exceptionSampleRates) == 0) {
  862.             return $sampleRate;
  863.         }
  864.         $exceptionClasses = array();
  865.         $class get_class($toLog);
  866.         while ($class) {
  867.             $exceptionClasses []= $class;
  868.             $class get_parent_class($class);
  869.         }
  870.         $exceptionClasses array_reverse($exceptionClasses);
  871.         foreach ($exceptionClasses as $exceptionClass) {
  872.             if (isset($this->exceptionSampleRates["$exceptionClass"])) {
  873.                 $sampleRate $this->exceptionSampleRates["$exceptionClass"];
  874.             }
  875.         }
  876.         return $sampleRate;
  877.     }
  878.     /**
  879.      * @param Payload $payload
  880.      * @return bool
  881.      */
  882.     private function payloadLevelTooLow(Payload $payload): bool
  883.     {
  884.         return $this->levelTooLow($payload->getData()->getLevel());
  885.     }
  886.     /**
  887.      * @param Level $level
  888.      * @return bool
  889.      */
  890.     private function levelTooLow(Level $level): bool
  891.     {
  892.         return $level->toInt() < $this->minimumLevel;
  893.     }
  894.     /**
  895.      * Decides if a given log message should be suppressed by policy.
  896.      * If so, then a debug message is emitted: "Ignoring (error reporting has been disabled in PHP config"
  897.      * @since 3.0.1
  898.      */
  899.     public function shouldSuppress(): bool
  900.     {
  901.         // report_suppressed option forces reporting regardless of PHP settings.
  902.         if ($this->reportSuppressed) {
  903.             return false;
  904.         }
  905.         $errorReporting error_reporting();
  906.         // For error control operator of PHP 8:
  907.         // > Prior to PHP 8.0.0, the error_reporting() called inside the
  908.         // > custom error handler always returned 0 if the error was
  909.         // > suppressed by the @ operator. As of PHP 8.0.0, it returns
  910.         // > the value E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR |
  911.         // > E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE.
  912.         // https://www.php.net/manual/en/language.operators.errorcontrol.php
  913.         if (version_compare(PHP_VERSION'8.0''ge') && $errorReporting === (
  914.             E_ERROR E_CORE_ERROR E_COMPILE_ERROR E_USER_ERROR E_RECOVERABLE_ERROR E_PARSE
  915.         )) {
  916.             return true;
  917.         }
  918.         // PHP 7 or manually disabled case:
  919.         return $errorReporting === 0;
  920.     }
  921.     public function send(EncodedPayload $payloadstring $accessToken): ?Response
  922.     {
  923.         if ($this->transmitting()) {
  924.             $response $this->sender->send($payload$accessToken);
  925.         } else {
  926.             $response = new Response(0"Not transmitting (transmitting disabled in configuration)");
  927.             $this->verboseLogger()->warning($response->getInfo());
  928.         }
  929.         if ($this->loggingPayload()) {
  930.             $this->logPayloadLogger()->debug(
  931.                 'Sending payload with ' get_class($this->sender) . ":\n" .
  932.                 $payload
  933.             );
  934.         }
  935.         return $response;
  936.     }
  937.     public function sendBatch(array $batchstring $accessToken): ?Response
  938.     {
  939.         if ($this->transmitting()) {
  940.             $this->sender->sendBatch($batch$accessToken);
  941.             return null;
  942.         } else {
  943.             $response = new Response(0"Not transmitting (transmitting disabled in configuration)");
  944.             $this->verboseLogger()->warning($response->getInfo());
  945.             return $response;
  946.         }
  947.     }
  948.     public function wait(string $accessToken$max 0): void
  949.     {
  950.         $this->verboseLogger()->debug("Sender waiting...");
  951.         $this->sender->wait($accessToken$max);
  952.     }
  953.     public function handleResponse(Payload $payloadResponse $response): void
  954.     {
  955.         if (!is_null($this->responseHandler)) {
  956.             $this->verboseLogger()->debug(
  957.                 'Applying custom response handler: ' get_class($this->responseHandler)
  958.             );
  959.             $this->responseHandler->handleResponse($payload$response);
  960.         }
  961.     }
  962. }