PageRenderTime 105ms CodeModel.GetById 85ms app.highlight 8ms RepoModel.GetById 9ms app.codeStats 0ms

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

https://gitlab.com/judielsm/Handora
PHP | 293 lines | 159 code | 33 blank | 101 comment | 15 complexity | cca497a0df73f19f88cb52c70e9db018 MD5 | raw file
  1<?php
  2
  3/*
  4 * This file is part of the Monolog package.
  5 *
  6 * (c) Jordi Boggiano <j.boggiano@seld.be>
  7 *
  8 * For the full copyright and license information, please view the LICENSE
  9 * file that was distributed with this source code.
 10 */
 11
 12namespace Monolog\Handler;
 13
 14use Monolog\Logger;
 15use Monolog\Formatter\LineFormatter;
 16
 17/**
 18 * Sends notifications through Slack API
 19 *
 20 * @author Greg Kedzierski <greg@gregkedzierski.com>
 21 * @see    https://api.slack.com/
 22 */
 23class SlackHandler extends SocketHandler
 24{
 25    /**
 26     * Slack API token
 27     * @var string
 28     */
 29    private $token;
 30
 31    /**
 32     * Slack channel (encoded ID or name)
 33     * @var string
 34     */
 35    private $channel;
 36
 37    /**
 38     * Name of a bot
 39     * @var string
 40     */
 41    private $username;
 42
 43    /**
 44     * Emoji icon name
 45     * @var string
 46     */
 47    private $iconEmoji;
 48
 49    /**
 50     * Whether the message should be added to Slack as attachment (plain text otherwise)
 51     * @var bool
 52     */
 53    private $useAttachment;
 54
 55    /**
 56     * Whether the the context/extra messages added to Slack as attachments are in a short style
 57     * @var bool
 58     */
 59    private $useShortAttachment;
 60
 61    /**
 62     * Whether the attachment should include context and extra data
 63     * @var bool
 64     */
 65    private $includeContextAndExtra;
 66
 67    /**
 68     * @var LineFormatter
 69     */
 70    private $lineFormatter;
 71
 72    /**
 73     * @param string      $token                  Slack API token
 74     * @param string      $channel                Slack channel (encoded ID or name)
 75     * @param string      $username               Name of a bot
 76     * @param bool        $useAttachment          Whether the message should be added to Slack as attachment (plain text otherwise)
 77     * @param string|null $iconEmoji              The emoji name to use (or null)
 78     * @param int         $level                  The minimum logging level at which this handler will be triggered
 79     * @param bool        $bubble                 Whether the messages that are handled can bubble up the stack or not
 80     * @param bool        $useShortAttachment     Whether the the context/extra messages added to Slack as attachments are in a short style
 81     * @param bool        $includeContextAndExtra Whether the attachment should include context and extra data
 82     */
 83    public function __construct($token, $channel, $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false)
 84    {
 85        if (!extension_loaded('openssl')) {
 86            throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler');
 87        }
 88
 89        parent::__construct('ssl://slack.com:443', $level, $bubble);
 90
 91        $this->token = $token;
 92        $this->channel = $channel;
 93        $this->username = $username;
 94        $this->iconEmoji = trim($iconEmoji, ':');
 95        $this->useAttachment = $useAttachment;
 96        $this->useShortAttachment = $useShortAttachment;
 97        $this->includeContextAndExtra = $includeContextAndExtra;
 98        if ($this->includeContextAndExtra) {
 99            $this->lineFormatter = new LineFormatter;
100        }
101    }
102
103    /**
104     * {@inheritdoc}
105     *
106     * @param  array  $record
107     * @return string
108     */
109    protected function generateDataStream($record)
110    {
111        $content = $this->buildContent($record);
112
113        return $this->buildHeader($content) . $content;
114    }
115
116    /**
117     * Builds the body of API call
118     *
119     * @param  array  $record
120     * @return string
121     */
122    private function buildContent($record)
123    {
124        $dataArray = $this->prepareContentData($record);
125
126        return http_build_query($dataArray);
127    }
128
129    /**
130     * Prepares content data
131     *
132     * @param  array $record
133     * @return array
134     */
135    protected function prepareContentData($record)
136    {
137        $dataArray = array(
138            'token'       => $this->token,
139            'channel'     => $this->channel,
140            'username'    => $this->username,
141            'text'        => '',
142            'attachments' => array()
143        );
144
145        if ($this->useAttachment) {
146            $attachment = array(
147                'fallback' => $record['message'],
148                'color'    => $this->getAttachmentColor($record['level'])
149            );
150
151            if ($this->useShortAttachment) {
152                $attachment['fields'] = array(
153                    array(
154                        'title' => $record['level_name'],
155                        'value' => $record['message'],
156                        'short' => false
157                    )
158                );
159            } else {
160                $attachment['fields'] = array(
161                    array(
162                        'title' => 'Message',
163                        'value' => $record['message'],
164                        'short' => false
165                    ),
166                    array(
167                        'title' => 'Level',
168                        'value' => $record['level_name'],
169                        'short' => true
170                    )
171                );
172            }
173
174            if ($this->includeContextAndExtra) {
175                if (!empty($record['extra'])) {
176                    if ($this->useShortAttachment) {
177                        $attachment['fields'][] = array(
178                            'title' => "Extra",
179                            'value' => $this->stringify($record['extra']),
180                            'short' => $this->useShortAttachment
181                        );
182                    } else {
183                        // Add all extra fields as individual fields in attachment
184                        foreach ($record['extra'] as $var => $val) {
185                            $attachment['fields'][] = array(
186                                'title' => $var,
187                                'value' => $val,
188                                'short' => $this->useShortAttachment
189                            );
190                        }
191                    }
192                }
193
194                if (!empty($record['context'])) {
195                    if ($this->useShortAttachment) {
196                        $attachment['fields'][] = array(
197                            'title' => "Context",
198                            'value' => $this->stringify($record['context']),
199                            'short' => $this->useShortAttachment
200                        );
201                    } else {
202                        // Add all context fields as individual fields in attachment
203                        foreach ($record['context'] as $var => $val) {
204                            $attachment['fields'][] = array(
205                                'title' => $var,
206                                'value' => $val,
207                                'short' => $this->useShortAttachment
208                            );
209                        }
210                    }
211                }
212            }
213
214            $dataArray['attachments'] = json_encode(array($attachment));
215        } else {
216            $dataArray['text'] = $record['message'];
217        }
218
219        if ($this->iconEmoji) {
220            $dataArray['icon_emoji'] = ":{$this->iconEmoji}:";
221        }
222
223        return $dataArray;
224    }
225
226    /**
227     * Builds the header of the API Call
228     *
229     * @param  string $content
230     * @return string
231     */
232    private function buildHeader($content)
233    {
234        $header = "POST /api/chat.postMessage HTTP/1.1\r\n";
235        $header .= "Host: slack.com\r\n";
236        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
237        $header .= "Content-Length: " . strlen($content) . "\r\n";
238        $header .= "\r\n";
239
240        return $header;
241    }
242
243    /**
244     * {@inheritdoc}
245     *
246     * @param array $record
247     */
248    protected function write(array $record)
249    {
250        parent::write($record);
251        $this->closeSocket();
252    }
253
254    /**
255     * Returned a Slack message attachment color associated with
256     * provided level.
257     *
258     * @param  int    $level
259     * @return string
260     */
261    protected function getAttachmentColor($level)
262    {
263        switch (true) {
264            case $level >= Logger::ERROR:
265                return 'danger';
266            case $level >= Logger::WARNING:
267                return 'warning';
268            case $level >= Logger::INFO:
269                return 'good';
270            default:
271                return '#e3e4e6';
272        }
273    }
274
275    /**
276     * Stringifies an array of key/value pairs to be used in attachment fields
277     *
278     * @param array $fields
279     * @access protected
280     * @return string
281     */
282    protected function stringify($fields)
283    {
284        $string = '';
285        foreach ($fields as $var => $val) {
286            $string .= $var.': '.$this->lineFormatter->stringify($val)." | ";
287        }
288
289        $string = rtrim($string, " |");
290
291        return $string;
292    }
293}