Просмотр исходного кода

HipChat Handler

Adds a handler that is capable of sending notices into HipChat, the team communication system provided by Atlassian.
This is based on the PushoverHandler and built on top of the socketHandler.

The needed configuration is described in the docblock of the HipChatHandler file.
Rafael Dohms 12 лет назад
Родитель
Сommit
0f13a1a6bb
3 измененных файлов с 265 добавлено и 0 удалено
  1. 1 0
      README.mdown
  2. 154 0
      src/Monolog/Handler/HipChatHandler.php
  3. 110 0
      tests/Monolog/Handler/HipChatHandlerTest.php

+ 1 - 0
README.mdown

@@ -115,6 +115,7 @@ Handlers
   [`mail()`](http://php.net/manual/en/function.mail.php) function.
 - _SwiftMailerHandler_: Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance.
 - _PushoverHandler_: Sends mobile notifications via the [Pushover](https://www.pushover.net/) API.
+- _HipChatHandler_: Logs records to a [HipChat](http://hipchat.com) chat room using its API.
 
 ### Log specific servers and networked logging
 

+ 154 - 0
src/Monolog/Handler/HipChatHandler.php

@@ -0,0 +1,154 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through the hipchat api to a hipchat room
+ *
+ * Notes:
+ * API token - HipChat API token
+ * Room      - HipChat Room Id or name, where messages are sent
+ * Name      - Name used to send the message (from)
+ * notify    - Should the message trigger a notification in the clients
+ *
+ * @author Rafael Dohms <rafael@doh.ms>
+ * @see    https://www.hipchat.com/docs/api
+ */
+class HipChatHandler extends SocketHandler
+{
+    /**
+     * @var string
+     */
+    private $token;
+
+    /**
+     * @var array
+     */
+    private $room;
+
+    /**
+     * @var string
+     */
+    private $name;
+
+    /**
+     * @var boolean
+     */
+    private $notify;
+
+    /**
+     * @param string $token  HipChat API Token
+     * @param string $room   The room that should be alerted of the message (Id or Name)
+     * @param string $name   Name used in the "from" field
+     * @param bool $notify   Trigger a notification in clients or not
+     * @param int $level     The minimum logging level at which this handler will be triggered
+     * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+     * @param Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
+     *                        the pushover.net app owner. OpenSSL is required for this option.
+     */
+    public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true)
+    {
+        $connectionString = $useSSL ? 'ssl://api.hipchat.com:443' : 'api.hipchat.com:80';
+        parent::__construct($connectionString, $level, $bubble);
+
+        $this->token = $token;
+        $this->name = $name;
+        $this->notify = $notify;
+        $this->room = $room;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param array $record
+     * @return string
+     */
+    protected function generateDataStream($record)
+    {
+        $content = $this->buildContent($record);
+
+        return $this->buildHeader($content) . $content;
+    }
+
+    /**
+     * Builds the body of API call
+     *
+     * @param array $record
+     * @return string
+     */
+    private function buildContent($record)
+    {
+        $dataArray = array(
+            'from' => $this->name,
+            'room_id' => $this->room,
+            'notify' => $this->notify,
+            'message' => $record['formatted'],
+            'message_format' => 'text',
+            'color' => $this->getAlertColor($record['level']),
+        );
+
+        return http_build_query($dataArray);
+    }
+
+    /**
+     * Builds the header of the API Call
+     *
+     * @param string $content
+     * @return string
+     */
+    private function buildHeader($content)
+    {
+        $header = "POST /v1/rooms/message?format=json&auth_token=".$this->token." HTTP/1.1\r\n";
+        $header .= "Host: api.hipchat.com\r\n";
+        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+        $header .= "Content-Length: " . strlen($content) . "\r\n";
+        $header .= "\r\n";
+
+        return $header;
+    }
+
+    /**
+     * Assigns a color to each level of log records.
+     *
+     * @param integer $level
+     * @return string
+     */
+    protected function getAlertColor($level)
+    {
+        switch (true) {
+            case $level >= Logger::ERROR:
+                return 'red';
+            case $level >= Logger::WARNING:
+                return 'yellow';
+            case $level >= Logger::INFO:
+                return 'green';
+            case $level == Logger::DEBUG:
+                return 'gray';
+            default:
+                return 'yellow';
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param array $record
+     */
+    public function write(array $record)
+    {
+        parent::write($record);
+        $this->closeSocket();
+    }
+
+}

+ 110 - 0
tests/Monolog/Handler/HipChatHandlerTest.php

@@ -0,0 +1,110 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @author Rafael Dohms <rafael@doh.ms>
+ * @see    https://www.hipchat.com/docs/api
+ */
+class HipChatHandlerTest extends TestCase
+{
+
+    private $res;
+    private $handler;
+
+    public function testWriteHeader()
+    {
+        $this->createHandler();
+        $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+        fseek($this->res, 0);
+        $content = fread($this->res, 1024);
+
+        $this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: api.hipchat.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+
+        return $content;
+    }
+
+    /**
+     * @depends testWriteHeader
+     */
+    public function testWriteContent($content)
+    {
+        $this->assertRegexp('/from=Monolog&room_id=room1&notify=0&message=test1&message_format=text&color=red$/', $content);
+    }
+
+    public function testWriteWithComplexMessage()
+    {
+        $this->createHandler();
+        $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.'));
+        fseek($this->res, 0);
+        $content = fread($this->res, 1024);
+
+        $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content);
+    }
+
+    /**
+     * @dataProvider provideLevelColors
+     */
+    public function testWriteWithErrorLevelsAndColors($level, $expectedColor)
+    {
+        $this->createHandler();
+        $this->handler->handle($this->getRecord($level, 'Backup of database "example" finished in 16 minutes.'));
+        fseek($this->res, 0);
+        $content = fread($this->res, 1024);
+
+        $this->assertRegexp('/color='.$expectedColor.'/', $content);
+    }
+
+    public function provideLevelColors()
+    {
+        return array(
+            array(Logger::DEBUG,    'gray'),
+            array(Logger::INFO,     'green'),
+            array(Logger::WARNING,  'yellow'),
+            array(Logger::ERROR,    'red'),
+            array(Logger::CRITICAL, 'red'),
+            array(Logger::ALERT,    'red'),
+            array(Logger::EMERGENCY,'red'),
+            array(Logger::NOTICE,   'green'),
+        );
+    }
+
+    private function createHandler($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false)
+    {
+        $constructorArgs = array($token, $room, $name, $notify, Logger::DEBUG);
+        $this->res = fopen('php://memory', 'a');
+        $this->handler = $this->getMock(
+            '\Monolog\Handler\HipChatHandler',
+            array('fsockopen', 'streamSetTimeout', 'closeSocket'),
+            $constructorArgs
+        );
+
+        $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->handler, 'localhost:1234');
+
+        $this->handler->expects($this->any())
+            ->method('fsockopen')
+            ->will($this->returnValue($this->res));
+        $this->handler->expects($this->any())
+            ->method('streamSetTimeout')
+            ->will($this->returnValue(true));
+        $this->handler->expects($this->any())
+            ->method('closeSocket')
+            ->will($this->returnValue(true));
+
+        $this->handler->setFormatter($this->getIdentityFormatter());
+    }
+}