NewRelicHandler.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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\Logger;
  12. use Monolog\Formatter\NormalizerFormatter;
  13. /**
  14. * Class to record a log on a NewRelic application.
  15. * Enabling New Relic High Security mode may prevent capture of useful information.
  16. *
  17. * @see https://docs.newrelic.com/docs/agents/php-agent
  18. * @see https://docs.newrelic.com/docs/accounts-partnerships/accounts/security/high-security
  19. */
  20. class NewRelicHandler extends AbstractProcessingHandler
  21. {
  22. /**
  23. * Name of the New Relic application that will receive logs from this handler.
  24. *
  25. * @var string
  26. */
  27. protected $appName;
  28. /**
  29. * Name of the current transaction
  30. *
  31. * @var string
  32. */
  33. protected $transactionName;
  34. /**
  35. * Some context and extra data is passed into the handler as arrays of values. Do we send them as is
  36. * (useful if we are using the API), or explode them for display on the NewRelic RPM website?
  37. *
  38. * @var bool
  39. */
  40. protected $explodeArrays;
  41. /**
  42. * {@inheritDoc}
  43. *
  44. * @param string $appName
  45. * @param bool $explodeArrays
  46. * @param string $transactionName
  47. */
  48. public function __construct(
  49. $level = Logger::ERROR,
  50. $bubble = true,
  51. $appName = null,
  52. $explodeArrays = false,
  53. $transactionName = null
  54. ) {
  55. parent::__construct($level, $bubble);
  56. $this->appName = $appName;
  57. $this->explodeArrays = $explodeArrays;
  58. $this->transactionName = $transactionName;
  59. }
  60. /**
  61. * {@inheritDoc}
  62. */
  63. protected function write(array $record)
  64. {
  65. if (!$this->isNewRelicEnabled()) {
  66. throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler');
  67. }
  68. if ($appName = $this->getAppName($record['context'])) {
  69. $this->setNewRelicAppName($appName);
  70. }
  71. if ($transactionName = $this->getTransactionName($record['context'])) {
  72. $this->setNewRelicTransactionName($transactionName);
  73. unset($record['formatted']['context']['transaction_name']);
  74. }
  75. if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
  76. newrelic_notice_error($record['message'], $record['context']['exception']);
  77. unset($record['formatted']['context']['exception']);
  78. } else {
  79. newrelic_notice_error($record['message']);
  80. }
  81. if (isset($record['formatted']['context']) && is_array($record['formatted']['context'])) {
  82. foreach ($record['formatted']['context'] as $key => $parameter) {
  83. if (is_array($parameter) && $this->explodeArrays) {
  84. foreach ($parameter as $paramKey => $paramValue) {
  85. $this->setNewRelicParameter('context_' . $key . '_' . $paramKey, $paramValue);
  86. }
  87. } else {
  88. $this->setNewRelicParameter('context_' . $key, $parameter);
  89. }
  90. }
  91. }
  92. if (isset($record['formatted']['extra']) && is_array($record['formatted']['extra'])) {
  93. foreach ($record['formatted']['extra'] as $key => $parameter) {
  94. if (is_array($parameter) && $this->explodeArrays) {
  95. foreach ($parameter as $paramKey => $paramValue) {
  96. $this->setNewRelicParameter('extra_' . $key . '_' . $paramKey, $paramValue);
  97. }
  98. } else {
  99. $this->setNewRelicParameter('extra_' . $key, $parameter);
  100. }
  101. }
  102. }
  103. }
  104. /**
  105. * Checks whether the NewRelic extension is enabled in the system.
  106. *
  107. * @return bool
  108. */
  109. protected function isNewRelicEnabled()
  110. {
  111. return extension_loaded('newrelic');
  112. }
  113. /**
  114. * Returns the appname where this log should be sent. Each log can override the default appname, set in this
  115. * handler's constructor, by providing the appname in it's context.
  116. *
  117. * @param array $context
  118. * @return null|string
  119. */
  120. protected function getAppName(array $context)
  121. {
  122. if (isset($context['appname'])) {
  123. return $context['appname'];
  124. }
  125. return $this->appName;
  126. }
  127. /**
  128. * Returns the name of the current transaction. Each log can override the default transaction name, set in this
  129. * handler's constructor, by providing the transaction_name in it's context
  130. *
  131. * @param array $context
  132. *
  133. * @return null|string
  134. */
  135. protected function getTransactionName(array $context)
  136. {
  137. if (isset($context['transaction_name'])) {
  138. return $context['transaction_name'];
  139. }
  140. return $this->transactionName;
  141. }
  142. /**
  143. * Sets the NewRelic application that should receive this log.
  144. *
  145. * @param string $appName
  146. */
  147. protected function setNewRelicAppName($appName)
  148. {
  149. newrelic_set_appname($appName);
  150. }
  151. /**
  152. * Overwrites the name of the current transaction
  153. *
  154. * @param string $transactionName
  155. */
  156. protected function setNewRelicTransactionName($transactionName)
  157. {
  158. newrelic_name_transaction($transactionName);
  159. }
  160. /**
  161. * @param string $key
  162. * @param mixed $value
  163. */
  164. protected function setNewRelicParameter($key, $value)
  165. {
  166. if (null === $value || is_scalar($value)) {
  167. newrelic_add_custom_parameter($key, $value);
  168. } else {
  169. newrelic_add_custom_parameter($key, @json_encode($value));
  170. }
  171. }
  172. /**
  173. * {@inheritDoc}
  174. */
  175. protected function getDefaultFormatter()
  176. {
  177. return new NormalizerFormatter();
  178. }
  179. }