mirror of
https://github.com/Seldaek/monolog.git
synced 2025-02-23 22:42:38 +01:00
Adding a first version of PushoverHandler
The PushoverHandler sends messages to api.pushover.net. The class depends on the SocketHandler I modified the SocketHandler to make it possible to change the port for subclasses (Pushover needs the explicit port 80 to work) The tests only see if the content sent to the api is correct. The rest should be already covered in the tests for the Sockets.
This commit is contained in:
parent
a929570bb7
commit
d6489bb3ae
92
src/Monolog/Handler/PushoverHandler.php
Normal file
92
src/Monolog/Handler/PushoverHandler.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?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 pushover api to mobile phones
|
||||
*
|
||||
* @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
|
||||
* @see https://www.pushover.net/api
|
||||
*/
|
||||
class PushoverHandler extends SocketHandler
|
||||
{
|
||||
private $token;
|
||||
private $user;
|
||||
private $title;
|
||||
|
||||
/**
|
||||
* @param string $token Pushover api token
|
||||
* @param string $user Pushover user id the message will be sent to
|
||||
* @param string $title Title sent to Pushover API
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct($token, $user, $title = 'Monolog error', $level = Logger::CRITICAL, $bubble = true)
|
||||
{
|
||||
parent::__construct('api.pushover.net', $level, $bubble);
|
||||
$this->conntectionPort = 80;
|
||||
|
||||
$this->token = $token;
|
||||
$this->user = $user;
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the content to be sent through the socket, then connect
|
||||
* (if necessary) and write to the socket
|
||||
*
|
||||
* @param array $record
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function write(array $record)
|
||||
{
|
||||
$data = $this->buildDataString($record);
|
||||
$content = $this->buildContent($data);
|
||||
$record['formatted'] = $content;
|
||||
|
||||
parent::write($record);
|
||||
}
|
||||
|
||||
private function buildContent($data)
|
||||
{
|
||||
$content = "POST /1/messages.json HTTP/1.1\r\n";
|
||||
$content .= "Host: api.pushover.net\r\n";
|
||||
$content .= "Content-Type: application/x-www-form-urlencoded\r\n";
|
||||
$content .= "Content-Length: " . strlen($data) . "\r\n";
|
||||
$content .= "\r\n";
|
||||
$content .= $data;
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
private function buildDataString($record)
|
||||
{
|
||||
// Pushover has a limit of 512 characters on title and message combined.
|
||||
$maxMessageLength = 512 - strlen($this->title);
|
||||
$message = substr($record['message'], 0, $maxMessageLength);
|
||||
$timestamp = $record['datetime']->getTimestamp();
|
||||
|
||||
$dataArray = array(
|
||||
'token' => $this->token,
|
||||
'user' => $this->user,
|
||||
'message' => $message,
|
||||
'title' => $this->title,
|
||||
'timestamp' => $timestamp
|
||||
);
|
||||
|
||||
return http_build_query($dataArray);
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ use Monolog\Logger;
|
||||
class SocketHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $connectionString;
|
||||
protected $conntectionPort = -1;
|
||||
private $connectionTimeout;
|
||||
private $resource;
|
||||
private $timeout = 0;
|
||||
@ -170,7 +171,7 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
protected function pfsockopen()
|
||||
{
|
||||
return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
|
||||
return @pfsockopen($this->connectionString, $this->conntectionPort, $this->errno, $this->errstr, $this->connectionTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,7 +179,7 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
protected function fsockopen()
|
||||
{
|
||||
return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
|
||||
return @fsockopen($this->connectionString, $this->conntectionPort, $this->errno, $this->errstr, $this->connectionTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -190,7 +191,7 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
{
|
||||
$seconds = floor($this->timeout);
|
||||
$microseconds = round(($this->timeout - $seconds)*1e6);
|
||||
|
||||
|
||||
return stream_set_timeout($this->resource, $seconds, $microseconds);
|
||||
}
|
||||
|
||||
|
107
tests/Monolog/Handler/PushoverHandlerTest.php
Normal file
107
tests/Monolog/Handler/PushoverHandlerTest.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Almost all examples (expected header, titles, messages) taken from
|
||||
* https://www.pushover.net/api
|
||||
* @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
|
||||
* @see https://www.pushover.net/api
|
||||
*/
|
||||
class PushoverHandlerTest 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 \/1\/messages.json HTTP\/1.1\\r\\nHost: api.pushover.net\\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('/token=myToken&user=myUser&message=test1&title=Monolog\+error×tamp=\d{10}$/', $content);
|
||||
}
|
||||
|
||||
public function testWriteWithComplexTitle()
|
||||
{
|
||||
$this->createHandler('myToken', 'myUser', 'Backup finished - SQL1');
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/title=Backup\+finished\+-\+SQL1/', $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);
|
||||
}
|
||||
|
||||
public function testWriteWithTooLongMessage()
|
||||
{
|
||||
$message = str_pad('test', 520, 'a');
|
||||
$this->createHandler();
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, $message));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$expectedMessage = substr($message, 0, 499);
|
||||
|
||||
$this->assertRegexp('/message=' . $expectedMessage . '&title/', $content);
|
||||
}
|
||||
|
||||
private function createHandler($token = 'myToken', $user = 'myUser', $title = null)
|
||||
{
|
||||
$constructArray = array($token, $user);
|
||||
if($title != null) {
|
||||
$constructArray[2] = $title;
|
||||
}
|
||||
$this->res = fopen('php://memory', 'a');
|
||||
$this->handler = $this->getMock(
|
||||
'\Monolog\Handler\PushoverHandler', array('fsockopen', 'streamSetTimeout'), $constructArray
|
||||
);
|
||||
|
||||
$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->setFormatter($this->getIdentityFormatter());
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user