You are here

public function Raven::log in Raven: Sentry Integration 3.x

Same name and namespace in other branches
  1. 8.2 src/Logger/Raven.php \Drupal\raven\Logger\Raven::log()
  2. 8 src/Logger/Raven.php \Drupal\raven\Logger\Raven::log()

Overrides RfcLoggerTrait::log

File

src/Logger/Raven.php, line 222

Class

Raven
Logs events to Sentry.

Namespace

Drupal\raven\Logger

Code

public function log($level, $message, array $context = []) {
  static $counter = 0;
  $client = $this
    ->getClient();
  if (!$client) {
    return;
  }
  $config = $this->configFactory
    ->get('raven.settings');
  $event = Event::createEvent();
  $levels = [
    RfcLogLevel::EMERGENCY => Severity::FATAL,
    RfcLogLevel::ALERT => Severity::FATAL,
    RfcLogLevel::CRITICAL => Severity::FATAL,
    RfcLogLevel::ERROR => Severity::ERROR,
    RfcLogLevel::WARNING => Severity::WARNING,
    RfcLogLevel::NOTICE => Severity::INFO,
    RfcLogLevel::INFO => Severity::INFO,
    RfcLogLevel::DEBUG => Severity::DEBUG,
  ];
  $event
    ->setLevel(new Severity($levels[$level]));
  $message_placeholders = $this->parser
    ->parseMessagePlaceholders($message, $context);
  $formatted_message = empty($message_placeholders) ? $message : strtr($message, $message_placeholders);
  $event
    ->setMessage($message, $message_placeholders, $formatted_message);
  $event
    ->setTimestamp($context['timestamp']);
  $event
    ->setLogger($context['channel']);
  $extra = [
    'request_uri' => $context['request_uri'],
  ];
  if ($context['referer']) {
    $extra['referer'] = $context['referer'];
  }
  if ($context['link']) {
    $extra['link'] = MailFormatHelper::htmlToText($context['link']);
  }
  $event
    ->setExtra($extra);
  $user = UserDataBag::createFromUserIdentifier($context['uid']);
  $user
    ->setIpAddress($context['ip']);
  if ($this->currentUser && $this->currentUser
    ->id() == $context['uid'] && $config
    ->get('send_user_data')) {
    $user
      ->setEmail($this->currentUser
      ->getEmail());
    $user
      ->setUsername($this->currentUser
      ->getAccountName());
  }
  $event
    ->setUser($user);
  if ($client
    ->getOptions()
    ->shouldAttachStacktrace()) {
    if (isset($context['backtrace'])) {
      $backtrace = $context['backtrace'];
      if (!$config
        ->get('trace')) {
        foreach ($backtrace as &$frame) {
          unset($frame['args']);
        }
      }
    }
    else {
      $backtrace = debug_backtrace($config
        ->get('trace') ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS);

      // Remove any logger stack frames.
      $finder = new ClassFinder();
      if ($backtrace[0]['file'] === realpath($finder
        ->findFile(LoggerChannel::class))) {
        array_shift($backtrace);
        if ($backtrace[0]['file'] === realpath($finder
          ->findFile(LoggerTrait::class))) {
          array_shift($backtrace);
        }
      }
    }
    $stacktraceBuilder = new StacktraceBuilder($client
      ->getOptions(), new RepresentationSerializer($client
      ->getOptions()));
    $stacktrace = $stacktraceBuilder
      ->buildFromBacktrace($backtrace, '', 0);
    $stacktrace
      ->removeFrame(count($stacktrace
      ->getFrames()) - 1);
    $event
      ->setStacktrace($stacktrace);
  }

  // Allow modules to alter or ignore this message.
  $filter = [
    'level' => $level,
    'message' => $message,
    'context' => $context,
    'event' => $event,
    'client' => $client,
    'process' => !empty($config
      ->get('log_levels')[$level + 1]),
  ];
  if (in_array($context['channel'], $config
    ->get('ignored_channels') ?: [])) {
    $filter['process'] = FALSE;
  }
  $this->moduleHandler
    ->alter('raven_filter', $filter);
  if (!empty($filter['process'])) {
    $eventHint['extra'] = [
      'level' => $level,
      'message' => $message,
      'context' => $context,
    ];
    if (isset($stacktrace)) {
      $eventHint['stacktrace'] = $stacktrace;
    }
    if (isset($context['exception']) && $context['exception'] instanceof \Throwable) {
      $eventHint['exception'] = $context['exception'];
    }
    $start = microtime(TRUE);
    $rateLimit = $config
      ->get('rate_limit');
    if (!$rateLimit || $counter < $rateLimit) {
      \Sentry\captureEvent($event, EventHint::fromArray($eventHint));
    }
    elseif ($counter == $rateLimit) {
      \Sentry\captureException(new RateLimitException('Log event discarded due to rate limit exceeded; future log events will not be captured by Sentry.'));
    }
    $counter++;
    if ($parent = SentrySdk::getCurrentHub()
      ->getSpan()) {
      $span = new SpanContext();
      $span
        ->setOp('sentry.capture');
      $span
        ->setDescription($context['channel'] . ': ' . $formatted_message);
      $span
        ->setStartTimestamp($start);
      $span
        ->setEndTimestamp(microtime(TRUE));
      $parent
        ->startChild($span);
    }
  }

  // Record a breadcrumb.
  $breadcrumb = [
    'level' => $level,
    'message' => $message,
    'context' => $context,
    'process' => TRUE,
    'breadcrumb' => [
      'category' => $context['channel'],
      'message' => isset($formatted_message) ? (string) $formatted_message : NULL,
      'level' => $levels[$level],
    ],
  ];
  foreach ([
    '%line',
    '%file',
    '%type',
    '%function',
  ] as $key) {
    if (isset($context[$key])) {
      $breadcrumb['breadcrumb']['data'][substr($key, 1)] = $context[$key];
    }
  }
  $this->moduleHandler
    ->alter('raven_breadcrumb', $breadcrumb);
  if (!empty($breadcrumb['process'])) {
    \Sentry\addBreadcrumb(Breadcrumb::fromArray($breadcrumb['breadcrumb']));
  }
}