Skip to content

Instantly share code, notes, and snippets.

@makasim
Last active May 31, 2019 20:05
Show Gist options
  • Save makasim/4b84cef705d54cc0487089ad360cf0e4 to your computer and use it in GitHub Desktop.
Save makasim/4b84cef705d54cc0487089ad360cf0e4 to your computer and use it in GitHub Desktop.
A monolog telegram handler that does not have negative impact on response time. Compose log records in a single message. Do not crush if telegram down
<?php
declare(strict_types=1);
namespace App\Infra\Monolog;
use GuzzleHttp\Client;
use Monolog\Handler\AbstractProcessingHandler;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\Service\ResetInterface;
class TelegramHandler extends AbstractProcessingHandler implements ResetInterface, EventSubscriberInterface
{
private $client;
private $token;
private $chat;
private $records;
private $flushThreshold;
private $fallbackLogger;
public function __construct(int $level, ?string $token, ?int $chat, LoggerInterface $fallbackLogger, int $flushThreshold = 10)
{
$this->level = $level;
$this->token = $token;
$this->chat = $chat;
$this->flushThreshold = $flushThreshold;
$this->fallbackLogger = $fallbackLogger;
$this->client = new Client();
$this->records = [];
parent::__construct($level, true);
}
public function flush(): void
{
$records = $this->records;
$this->records = [];
$message = '';
foreach ($records as $record) {
$recordMessage = $record['formatted'];
if (mb_strlen($recordMessage) >= 4096) {
$recordMessage = mb_substr($recordMessage, 0, 4092).' ...';
}
if ((mb_strlen($message) + mb_strlen($recordMessage)) >= 4096) {
$this->send($message);
$message = '';
}
$message .= $recordMessage.PHP_EOL.PHP_EOL;
}
if ($message) {
$this->send($message);
}
}
public function reset(): void
{
$this->records = [];
parent::reset();
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::TERMINATE => ['flush', -512],
ConsoleEvents::TERMINATE => ['flush', -512],
];
}
protected function write(array $record): void
{
if (isset($record['context']['skip_telegram_handler']) && $record['context']['skip_telegram_handler']) {
return;
}
if (null === $this->token || null === $this->chat) {
return;
}
$this->records[] = $record;
if (count($this->records) >= $this->flushThreshold) {
$this->flush();
}
}
protected function send(string $message): void
{
try {
$this->client->post('https://api.telegram.org/bot'.$this->token.'/sendMessage', [
'form_params' => [
'chat_id' => $this->chat,
'text' => $message,
],
]);
} catch (\Throwable $e) {
$this->fallbackLogger->error('telegram_logger: cannot send log message to telegram', [
'skip_telegram_handler' => true,
'exception' => $e,
]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment