MonologHandlerHipChatHandler

Sends notifications through the hipchat api to a hipchat room.

Defined (1)

The class is defined in the following location(s).

/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php  
  1. class HipChatHandler extends SocketHandler 
  2. /** 
  3. * Use API version 1 
  4. */ 
  5. const API_V1 = 'v1'; 
  6.  
  7. /** 
  8. * Use API version v2 
  9. */ 
  10. const API_V2 = 'v2'; 
  11.  
  12. /** 
  13. * The maximum allowed length for the name used in the "from" field. 
  14. */ 
  15. const MAXIMUM_NAME_LENGTH = 15; 
  16.  
  17. /** 
  18. * The maximum allowed length for the message. 
  19. */ 
  20. const MAXIMUM_MESSAGE_LENGTH = 9500; 
  21.  
  22. /** 
  23. * @var string 
  24. */ 
  25. private $token; 
  26.  
  27. /** 
  28. * @var string 
  29. */ 
  30. private $room; 
  31.  
  32. /** 
  33. * @var string 
  34. */ 
  35. private $name; 
  36.  
  37. /** 
  38. * @var bool 
  39. */ 
  40. private $notify; 
  41.  
  42. /** 
  43. * @var string 
  44. */ 
  45. private $format; 
  46.  
  47. /** 
  48. * @var string 
  49. */ 
  50. private $host; 
  51.  
  52. /** 
  53. * @var string 
  54. */ 
  55. private $version; 
  56.  
  57. /** 
  58. * @param string $token HipChat API Token 
  59. * @param string $room The room that should be alerted of the message (Id or Name) 
  60. * @param string $name Name used in the "from" field. Not used for v2 
  61. * @param bool $notify Trigger a notification in clients or not 
  62. * @param int $level The minimum logging level at which this handler will be triggered 
  63. * @param bool $bubble Whether the messages that are handled can bubble up the stack or not 
  64. * @param bool $useSSL Whether to connect via SSL. 
  65. * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages) 
  66. * @param string $host The HipChat server hostname. 
  67. * @param string $version The HipChat API version (default HipChatHandler::API_V1) 
  68. */ 
  69. public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1) 
  70. if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) { 
  71. throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.'); 
  72.  
  73. $connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80'; 
  74. parent::__construct($connectionString, $level, $bubble); 
  75.  
  76. $this->token = $token; 
  77. $this->name = $name; 
  78. $this->notify = $notify; 
  79. $this->room = $room; 
  80. $this->format = $format; 
  81. $this->host = $host; 
  82. $this->version = $version; 
  83.  
  84. /** 
  85. * {@inheritdoc} 
  86. * @param array $record 
  87. * @return string 
  88. */ 
  89. protected function generateDataStream($record) 
  90. $content = $this->buildContent($record); 
  91.  
  92. return $this->buildHeader($content) . $content; 
  93.  
  94. /** 
  95. * Builds the body of API call 
  96. * @param array $record 
  97. * @return string 
  98. */ 
  99. private function buildContent($record) 
  100. $dataArray = array( 
  101. 'notify' => $this->version == self::API_V1 ? 
  102. ($this->notify ? 1 : 0) : 
  103. ($this->notify ? 'true' : 'false'),  
  104. 'message' => $record['formatted'],  
  105. 'message_format' => $this->format,  
  106. 'color' => $this->getAlertColor($record['level']),  
  107. ); 
  108.  
  109. // if we are using the legacy API then we need to send some additional information 
  110. if ($this->version == self::API_V1) { 
  111. $dataArray['room_id'] = $this->room; 
  112. $dataArray['from'] = $this->name; 
  113.  
  114. return http_build_query($dataArray); 
  115.  
  116. /** 
  117. * Builds the header of the API Call 
  118. * @param string $content 
  119. * @return string 
  120. */ 
  121. private function buildHeader($content) 
  122. if ($this->version == self::API_V1) { 
  123. $header = "POST /v1/rooms/message?format=json&auth_token={$this->token} HTTP/1.1\r\n"; 
  124. } else { 
  125. // needed for rooms with special (spaces, etc) characters in the name 
  126. $room = rawurlencode($this->room); 
  127. $header = "POST /v2/room/{$room}/notification?auth_token={$this->token} HTTP/1.1\r\n"; 
  128.  
  129. $header .= "Host: {$this->host}\r\n"; 
  130. $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; 
  131. $header .= "Content-Length: " . strlen($content) . "\r\n"; 
  132. $header .= "\r\n"; 
  133.  
  134. return $header; 
  135.  
  136. /** 
  137. * Assigns a color to each level of log records. 
  138. * @param integer $level 
  139. * @return string 
  140. */ 
  141. protected function getAlertColor($level) 
  142. switch (true) { 
  143. case $level >= Logger::ERROR: 
  144. return 'red'; 
  145. case $level >= Logger::WARNING: 
  146. return 'yellow'; 
  147. case $level >= Logger::INFO: 
  148. return 'green'; 
  149. case $level == Logger::DEBUG: 
  150. return 'gray'; 
  151. default: 
  152. return 'yellow'; 
  153.  
  154. /** 
  155. * {@inheritdoc} 
  156. * @param array $record 
  157. */ 
  158. protected function write(array $record) 
  159. parent::write($record); 
  160. $this->closeSocket(); 
  161.  
  162. /** 
  163. * {@inheritdoc} 
  164. */ 
  165. public function handleBatch(array $records) 
  166. if (count($records) == 0) { 
  167. return true; 
  168.  
  169. $batchRecords = $this->combineRecords($records); 
  170.  
  171. $handled = false; 
  172. foreach ($batchRecords as $batchRecord) { 
  173. if ($this->isHandling($batchRecord)) { 
  174. $this->write($batchRecord); 
  175. $handled = true; 
  176.  
  177. if (!$handled) { 
  178. return false; 
  179.  
  180. return false === $this->bubble; 
  181.  
  182. /** 
  183. * Combines multiple records into one. Error level of the combined record 
  184. * will be the highest level from the given records. Datetime will be taken 
  185. * from the first record. 
  186. * @param $records 
  187. * @return array 
  188. */ 
  189. private function combineRecords($records) 
  190. $batchRecord = null; 
  191. $batchRecords = array(); 
  192. $messages = array(); 
  193. $formattedMessages = array(); 
  194. $level = 0; 
  195. $levelName = null; 
  196. $datetime = null; 
  197.  
  198. foreach ($records as $record) { 
  199. $record = $this->processRecord($record); 
  200.  
  201. if ($record['level'] > $level) { 
  202. $level = $record['level']; 
  203. $levelName = $record['level_name']; 
  204.  
  205. if (null === $datetime) { 
  206. $datetime = $record['datetime']; 
  207.  
  208. $messages[] = $record['message']; 
  209. $messageStr = implode(PHP_EOL, $messages); 
  210. $formattedMessages[] = $this->getFormatter()->format($record); 
  211. $formattedMessageStr = implode('', $formattedMessages); 
  212.  
  213. $batchRecord = array( 
  214. 'message' => $messageStr,  
  215. 'formatted' => $formattedMessageStr,  
  216. 'context' => array(),  
  217. 'extra' => array(),  
  218. ); 
  219.  
  220. if (!$this->validateStringLength($batchRecord['formatted'], static::MAXIMUM_MESSAGE_LENGTH)) { 
  221. // Pop the last message and implode the remaining messages 
  222. $lastMessage = array_pop($messages); 
  223. $lastFormattedMessage = array_pop($formattedMessages); 
  224. $batchRecord['message'] = implode(PHP_EOL, $messages); 
  225. $batchRecord['formatted'] = implode('', $formattedMessages); 
  226.  
  227. $batchRecords[] = $batchRecord; 
  228. $messages = array($lastMessage); 
  229. $formattedMessages = array($lastFormattedMessage); 
  230.  
  231. $batchRecord = null; 
  232.  
  233. if (null !== $batchRecord) { 
  234. $batchRecords[] = $batchRecord; 
  235.  
  236. // Set the max level and datetime for all records 
  237. foreach ($batchRecords as &$batchRecord) { 
  238. $batchRecord = array_merge( 
  239. $batchRecord,  
  240. array( 
  241. 'level' => $level,  
  242. 'level_name' => $levelName,  
  243. 'datetime' => $datetime 
  244. ); 
  245.  
  246. return $batchRecords; 
  247.  
  248. /** 
  249. * Validates the length of a string. 
  250. * If the `mb_strlen()` function is available, it will use that, as HipChat 
  251. * allows UTF-8 characters. Otherwise, it will fall back to `strlen()`. 
  252. * Note that this might cause false failures in the specific case of using 
  253. * a valid name with less than 16 characters, but 16 or more bytes, on a 
  254. * system where `mb_strlen()` is unavailable. 
  255. * @param string $str 
  256. * @param int $length 
  257. * @return bool 
  258. */ 
  259. private function validateStringLength($str, $length) 
  260. if (function_exists('mb_strlen')) { 
  261. return (mb_strlen($str) <= $length); 
  262.  
  263. return (strlen($str) <= $length);