PageRenderTime 39ms CodeModel.GetById 6ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php

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