RavenHandler.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. /*
  3. * This file is part of the Monolog package.
  4. *
  5. * (c) Jordi Boggiano <j.boggiano@seld.be>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Monolog\Handler;
  11. use Monolog\Formatter\LineFormatter;
  12. use Monolog\Formatter\FormatterInterface;
  13. use Monolog\Logger;
  14. use Raven_Client;
  15. /**
  16. * Handler to send messages to a Sentry (https://github.com/dcramer/sentry) server
  17. * using raven-php (https://github.com/getsentry/raven-php)
  18. *
  19. * @author Marc Abramowitz <marc@marc-abramowitz.com>
  20. */
  21. class RavenHandler extends AbstractProcessingHandler
  22. {
  23. /**
  24. * Translates Monolog log levels to Raven log levels.
  25. */
  26. private $logLevels = array(
  27. Logger::DEBUG => Raven_Client::DEBUG,
  28. Logger::INFO => Raven_Client::INFO,
  29. Logger::NOTICE => Raven_Client::INFO,
  30. Logger::WARNING => Raven_Client::WARNING,
  31. Logger::ERROR => Raven_Client::ERROR,
  32. Logger::CRITICAL => Raven_Client::FATAL,
  33. Logger::ALERT => Raven_Client::FATAL,
  34. Logger::EMERGENCY => Raven_Client::FATAL,
  35. );
  36. /**
  37. * @var Raven_Client the client object that sends the message to the server
  38. */
  39. protected $ravenClient;
  40. /**
  41. * @var LineFormatter The formatter to use for the logs generated via handleBatch()
  42. */
  43. protected $batchFormatter;
  44. /**
  45. * @param Raven_Client $ravenClient
  46. * @param integer $level The minimum logging level at which this handler will be triggered
  47. * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
  48. */
  49. public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
  50. {
  51. parent::__construct($level, $bubble);
  52. $this->ravenClient = $ravenClient;
  53. }
  54. /**
  55. * {@inheritdoc}
  56. */
  57. public function handleBatch(array $records)
  58. {
  59. $level = $this->level;
  60. // filter records based on their level
  61. $records = array_filter($records, function ($record) use ($level) {
  62. return $record['level'] >= $level;
  63. });
  64. if (!$records) {
  65. return;
  66. }
  67. // the record with the highest severity is the "main" one
  68. $record = array_reduce($records, function ($highest, $record) {
  69. if ($record['level'] >= $highest['level']) {
  70. return $record;
  71. }
  72. return $highest;
  73. });
  74. // the other ones are added as a context item
  75. $logs = array();
  76. foreach ($records as $r) {
  77. $logs[] = $this->processRecord($r);
  78. }
  79. if ($logs) {
  80. $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs);
  81. }
  82. $this->handle($record);
  83. }
  84. /**
  85. * Sets the formatter for the logs generated by handleBatch().
  86. *
  87. * @param FormatterInterface $formatter
  88. */
  89. public function setBatchFormatter(FormatterInterface $formatter)
  90. {
  91. $this->batchFormatter = $formatter;
  92. }
  93. /**
  94. * Gets the formatter for the logs generated by handleBatch().
  95. *
  96. * @return FormatterInterface
  97. */
  98. public function getBatchFormatter()
  99. {
  100. if (!$this->batchFormatter) {
  101. $this->batchFormatter = $this->getDefaultBatchFormatter();
  102. }
  103. return $this->batchFormatter;
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. protected function write(array $record)
  109. {
  110. $options = array();
  111. $options['level'] = $this->logLevels[$record['level']];
  112. $options['tags'] = array();
  113. if (!empty($record['extra']['tags'])) {
  114. $options['tags'] = array_merge($options['tags'], $record['extra']['tags']);
  115. unset($record['extra']['tags']);
  116. }
  117. if (!empty($record['context']['tags'])) {
  118. $options['tags'] = array_merge($options['tags'], $record['context']['tags']);
  119. unset($record['context']['tags']);
  120. }
  121. if (!empty($record['context'])) {
  122. $options['extra']['context'] = $record['context'];
  123. }
  124. if (!empty($record['extra'])) {
  125. $options['extra']['extra'] = $record['extra'];
  126. }
  127. if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
  128. $options['extra']['message'] = $record['formatted'];
  129. $this->ravenClient->captureException($record['context']['exception'], $options);
  130. return;
  131. }
  132. $this->ravenClient->captureMessage($record['formatted'], array(), $options);
  133. }
  134. /**
  135. * {@inheritDoc}
  136. */
  137. protected function getDefaultFormatter()
  138. {
  139. return new LineFormatter('[%channel%] %message%');
  140. }
  141. /**
  142. * Gets the default formatter for the logs generated by handleBatch().
  143. *
  144. * @return FormatterInterface
  145. */
  146. protected function getDefaultBatchFormatter()
  147. {
  148. return new LineFormatter();
  149. }
  150. }