4 * This file is part of the Monolog package.
6 * (c) Jordi Boggiano <j.boggiano@seld.be>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Monolog\Handler;
17 * Sends notifications through the pushover api to mobile phones
19 * @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
20 * @see https://www.pushover.net/api
22 class PushoverHandler extends SocketHandler
31 private $highPriorityLevel;
32 private $emergencyLevel;
33 private $useFormattedMessage = false;
36 * All parameters that can be sent to Pushover
37 * @see https://pushover.net/api
40 private $parameterNames = array(
57 * Sounds the api supports by default
58 * @see https://pushover.net/api#sounds
61 private $sounds = array(
62 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming',
63 'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb',
64 'persistent', 'echo', 'updown', 'none',
68 * @param string $token Pushover api token
69 * @param string|array $users Pushover user id or array of ids the message will be sent to
70 * @param string $title Title sent to the Pushover API
71 * @param int $level The minimum logging level at which this handler will be triggered
72 * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
73 * @param Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
74 * the pushover.net app owner. OpenSSL is required for this option.
75 * @param int $highPriorityLevel The minimum logging level at which this handler will start
76 * sending "high priority" requests to the Pushover API
77 * @param int $emergencyLevel The minimum logging level at which this handler will start
78 * sending "emergency" requests to the Pushover API
79 * @param int $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user.
80 * @param int $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds).
82 public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200)
84 $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80';
85 parent::__construct($connectionString, $level, $bubble);
87 $this->token = $token;
88 $this->users = (array) $users;
89 $this->title = $title ?: gethostname();
90 $this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel);
91 $this->emergencyLevel = Logger::toMonologLevel($emergencyLevel);
92 $this->retry = $retry;
93 $this->expire = $expire;
96 protected function generateDataStream($record)
98 $content = $this->buildContent($record);
100 return $this->buildHeader($content) . $content;
103 private function buildContent($record)
105 // Pushover has a limit of 512 characters on title and message combined.
106 $maxMessageLength = 512 - strlen($this->title);
108 $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message'];
109 $message = substr($message, 0, $maxMessageLength);
111 $timestamp = $record['datetime']->getTimestamp();
114 'token' => $this->token,
115 'user' => $this->user,
116 'message' => $message,
117 'title' => $this->title,
118 'timestamp' => $timestamp,
121 if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) {
122 $dataArray['priority'] = 2;
123 $dataArray['retry'] = $this->retry;
124 $dataArray['expire'] = $this->expire;
125 } elseif (isset($record['level']) && $record['level'] >= $this->highPriorityLevel) {
126 $dataArray['priority'] = 1;
129 // First determine the available parameters
130 $context = array_intersect_key($record['context'], $this->parameterNames);
131 $extra = array_intersect_key($record['extra'], $this->parameterNames);
133 // Least important info should be merged with subsequent info
134 $dataArray = array_merge($extra, $context, $dataArray);
136 // Only pass sounds that are supported by the API
137 if (isset($dataArray['sound']) && !in_array($dataArray['sound'], $this->sounds)) {
138 unset($dataArray['sound']);
141 return http_build_query($dataArray);
144 private function buildHeader($content)
146 $header = "POST /1/messages.json HTTP/1.1\r\n";
147 $header .= "Host: api.pushover.net\r\n";
148 $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
149 $header .= "Content-Length: " . strlen($content) . "\r\n";
155 protected function write(array $record)
157 foreach ($this->users as $user) {
160 parent::write($record);
161 $this->closeSocket();
167 public function setHighPriorityLevel($value)
169 $this->highPriorityLevel = $value;
172 public function setEmergencyLevel($value)
174 $this->emergencyLevel = $value;
178 * Use the formatted message?
181 public function useFormattedMessage($value)
183 $this->useFormattedMessage = (boolean) $value;