CubeHandler.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. /**
  13. * Logs to Cube.
  14. *
  15. * @link http://square.github.com/cube/
  16. * @author Wan Chen <kami@kamisama.me>
  17. */
  18. class CubeHandler extends AbstractProcessingHandler
  19. {
  20. private $udpConnection;
  21. private $httpConnection;
  22. private $scheme;
  23. private $host;
  24. private $port;
  25. private $acceptedSchemes = array('http', 'udp');
  26. /**
  27. * Create a Cube handler
  28. *
  29. * @throws \UnexpectedValueException when given url is not a valid url.
  30. * A valid url must consist of three parts : protocol://host:port
  31. * Only valid protocols used by Cube are http and udp
  32. */
  33. public function __construct($url, $level = Logger::DEBUG, $bubble = true)
  34. {
  35. $urlInfo = parse_url($url);
  36. if (!isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) {
  37. throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
  38. }
  39. if (!in_array($urlInfo['scheme'], $this->acceptedSchemes)) {
  40. throw new \UnexpectedValueException(
  41. 'Invalid protocol (' . $urlInfo['scheme'] . ').'
  42. . ' Valid options are ' . implode(', ', $this->acceptedSchemes));
  43. }
  44. $this->scheme = $urlInfo['scheme'];
  45. $this->host = $urlInfo['host'];
  46. $this->port = $urlInfo['port'];
  47. parent::__construct($level, $bubble);
  48. }
  49. /**
  50. * Establish a connection to an UDP socket
  51. *
  52. * @throws \LogicException when unable to connect to the socket
  53. * @throws MissingExtensionException when there is no socket extension
  54. */
  55. protected function connectUdp()
  56. {
  57. if (!extension_loaded('sockets')) {
  58. throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler');
  59. }
  60. $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0);
  61. if (!$this->udpConnection) {
  62. throw new \LogicException('Unable to create a socket');
  63. }
  64. if (!socket_connect($this->udpConnection, $this->host, $this->port)) {
  65. throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port);
  66. }
  67. }
  68. /**
  69. * Establish a connection to a http server
  70. * @throws \LogicException when no curl extension
  71. */
  72. protected function connectHttp()
  73. {
  74. if (!extension_loaded('curl')) {
  75. throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler');
  76. }
  77. $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put');
  78. if (!$this->httpConnection) {
  79. throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port);
  80. }
  81. curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST");
  82. curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true);
  83. }
  84. /**
  85. * {@inheritdoc}
  86. */
  87. protected function write(array $record)
  88. {
  89. $date = $record['datetime'];
  90. $data = array('time' => $date->format('Y-m-d\TH:i:s.uO'));
  91. unset($record['datetime']);
  92. if (isset($record['context']['type'])) {
  93. $data['type'] = $record['context']['type'];
  94. unset($record['context']['type']);
  95. } else {
  96. $data['type'] = $record['channel'];
  97. }
  98. $data['data'] = $record['context'];
  99. $data['data']['level'] = $record['level'];
  100. if ($this->scheme === 'http') {
  101. $this->writeHttp(json_encode($data));
  102. } else {
  103. $this->writeUdp(json_encode($data));
  104. }
  105. }
  106. private function writeUdp($data)
  107. {
  108. if (!$this->udpConnection) {
  109. $this->connectUdp();
  110. }
  111. socket_send($this->udpConnection, $data, strlen($data), 0);
  112. }
  113. private function writeHttp($data)
  114. {
  115. if (!$this->httpConnection) {
  116. $this->connectHttp();
  117. }
  118. curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']');
  119. curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array(
  120. 'Content-Type: application/json',
  121. 'Content-Length: ' . strlen('['.$data.']'))
  122. );
  123. Curl\Util::execute($this->httpConnection, 5, false);
  124. }
  125. }