hub = $hub; } /** * {@inheritdoc} */ public function handleBatch(array $records): void { $level = $this->level; // filter records based on their level $records = array_filter( $records, function ($record) use ($level) { return $record['level'] >= $level; } ); if (!$records) { return; } // the record with the highest severity is the "main" one $record = array_reduce( $records, function ($highest, $record) { if ($record['level'] > $highest['level']) { return $record; } return $highest; } ); // the other ones are added as a context item $logs = []; foreach ($records as $r) { $logs[] = $this->processRecord($r); } if ($logs) { $record['context']['logs'] = (string)$this->getBatchFormatter()->formatBatch($logs); } $this->handle($record); } /** * Sets the formatter for the logs generated by handleBatch(). * * @param FormatterInterface $formatter * * @return \Sentry\Laravel\SentryHandler */ public function setBatchFormatter(FormatterInterface $formatter): self { $this->batchFormatter = $formatter; return $this; } /** * Gets the formatter for the logs generated by handleBatch(). */ public function getBatchFormatter(): FormatterInterface { if (!$this->batchFormatter) { $this->batchFormatter = $this->getDefaultBatchFormatter(); } return $this->batchFormatter; } /** * Translates Monolog log levels to Sentry Severity. * * @param int $logLevel * * @return \Sentry\Severity */ protected function getLogLevel($logLevel) { switch ($logLevel) { case Logger::DEBUG: return Severity::debug(); case Logger::NOTICE: case Logger::INFO: return Severity::info(); case Logger::WARNING: return Severity::warning(); case Logger::ERROR: return Severity::error(); case Logger::ALERT: case Logger::EMERGENCY: case Logger::CRITICAL: return Severity::fatal(); } } /** * {@inheritdoc} * @suppress PhanTypeMismatchArgument */ protected function write(array $record): void { $this->hub->withScope( function (Scope $scope) use ($record) { if (!empty($record['context']['extra'])) { foreach ($record['context']['extra'] as $key => $tag) { $scope->setExtra($key, $tag); } unset($record['context']['extra']); } if (!empty($record['context']['tags'])) { foreach ($record['context']['tags'] as $key => $tag) { $scope->setTag($key, $tag); } unset($record['context']['tags']); } if (!empty($record['extra'])) { foreach ($record['extra'] as $key => $extra) { $scope->setExtra($key, $extra); } } if (!empty($record['context']['fingerprint'])) { $scope->setFingerprint($record['context']['fingerprint']); unset($record['context']['fingerprint']); } if (!empty($record['context']['user'])) { $scope->setUser((array)$record['context']['user'], true); unset($record['context']['user']); } $scope->addEventProcessor( function (Event $event) use ($record) { if (!empty($record['context']['logger'])) { $event->setLogger($record['context']['logger']); unset($record['context']['logger']); } else { $event->setLogger($record['channel']); } if (!empty($this->environment) && !$event->getEnvironment()) { $event->setEnvironment($this->environment); } if (!empty($this->release) && !$event->getRelease()) { $event->setRelease($this->release); } if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { $event->setMessage($record['formatted']); } return $event; } ); if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { $this->hub->captureException($record['context']['exception']); } else { $this->hub->captureMessage($record['formatted'], $this->getLogLevel($record['level'])); } } ); } /** * {@inheritDoc} */ protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('[%channel%] %message%'); } /** * Gets the default formatter for the logs generated by handleBatch(). * * @return FormatterInterface */ protected function getDefaultBatchFormatter(): FormatterInterface { return new LineFormatter(); } /** * Set the release. * * @param string $value * * @return self */ public function setRelease($value): self { $this->release = $value; return $this; } /** * Set the current application environment. * * @param string $value * * @return self */ public function setEnvironment($value): self { $this->environment = $value; return $this; } /** * Add a breadcrumb. * * @link https://docs.sentry.io/learn/breadcrumbs/ * * @param \Sentry\Breadcrumb $crumb * * @return \Sentry\Laravel\SentryHandler */ public function addBreadcrumb(Breadcrumb $crumb): self { $this->hub->addBreadcrumb($crumb); return $this; } }