├── .gitignore ├── src ├── views │ ├── minimal.blade.php │ └── standard.blade.php ├── TelegramLogger.php ├── TelegramLoggerServiceProvider.php └── TelegramHandler.php ├── composer.json ├── config └── telegram-logger.php ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | vendor/ 3 | composer.lock 4 | -------------------------------------------------------------------------------- /src/views/minimal.blade.php: -------------------------------------------------------------------------------- 1 | {{ $appName }} ({{ $level_name }}) 2 | {{ $formatted }} -------------------------------------------------------------------------------- /src/views/standard.blade.php: -------------------------------------------------------------------------------- 1 | {{ $appName }} ({{ $level_name }}) 2 | Env: {{ $appEnv }} 3 | [{{ $datetime->format('Y-m-d H:i:s') }}] {{ $appEnv }}.{{ $level_name }} {{ $formatted }} -------------------------------------------------------------------------------- /src/TelegramLogger.php: -------------------------------------------------------------------------------- 1 | env('TELEGRAM_LOGGER_BOT_TOKEN'), 6 | 7 | // Telegram chat id 8 | 'chat_id' => env('TELEGRAM_LOGGER_CHAT_ID'), 9 | 10 | // Telegram message thread id 11 | 'message_thread_id' => env('TELEGRAM_LOGGER_MESSAGE_THREAD_ID', null), 12 | 13 | // Blade Template to use formatting logs 14 | 'template' => env('TELEGRAM_LOGGER_TEMPLATE', 'laravel-telegram-logging::standard'), 15 | 16 | // Proxy server 17 | 'proxy' => env('TELEGRAM_LOGGER_PROXY', ''), 18 | 19 | // Telegram API host without trailling slash 20 | 'api_host' => env('TELEGRAM_LOGGER_API_HOST', 'https://api.telegram.org'), 21 | 22 | // Telegram sendMessage options: https://core.telegram.org/bots/api#sendmessage 23 | 'options' => [ 24 | // 'parse_mode' => 'html', 25 | // 'disable_web_page_preview' => true, 26 | // 'disable_notification' => false 27 | ] 28 | ]; 29 | -------------------------------------------------------------------------------- /src/TelegramLoggerServiceProvider.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom(__DIR__ . '/../config/telegram-logger.php', 'telegram-logger'); 21 | } 22 | 23 | /** 24 | * Perform post-registration booting of services. 25 | * 26 | * @return void 27 | */ 28 | public function boot() 29 | { 30 | $this->loadViewsFrom(__DIR__.'/views', 'laravel-telegram-logging'); 31 | $this->publishes([__DIR__.'/views' => base_path('resources/views/vendor/laravel-telegram-logging')], 'views'); 32 | $this->publishes([__DIR__ . '/../config/telegram-logger.php' => config_path('telegram-logger.php')], 'config'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Darius Matulionis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Telegram logger 2 | 3 | Send logs to Telegram chat via Telegram bot 4 | 5 | ## Install 6 | 7 | ``` 8 | 9 | composer require grkamil/laravel-telegram-logging 10 | 11 | ``` 12 | 13 | Define Telegram Bot Token and chat id (users telegram id) and set as environment parameters. 14 | Add to .env 15 | 16 | ``` 17 | TELEGRAM_LOGGER_BOT_TOKEN=id:token 18 | TELEGRAM_LOGGER_CHAT_ID=chat_id 19 | ``` 20 | 21 | 22 | Add to config/logging.php file new channel: 23 | 24 | ```php 25 | 'telegram' => [ 26 | 'driver' => 'custom', 27 | 'via' => Logger\TelegramLogger::class, 28 | 'level' => 'debug', 29 | ] 30 | ``` 31 | 32 | If your default log channel is a stack, you can add it to the stack channel like this 33 | ```php 34 | 'stack' => [ 35 | 'driver' => 'stack', 36 | 'channels' => ['single', 'telegram'], 37 | ] 38 | ``` 39 | 40 | Or you can simply change the default log channel in the .env 41 | ``` 42 | LOG_CHANNEL=telegram 43 | ``` 44 | 45 | Publish config file and views 46 | ``` 47 | php artisan vendor:publish --provider "Logger\TelegramLoggerServiceProvider" 48 | ``` 49 | 50 | ## Telegram Logging Formats 51 | 52 | You can choose among two different formats that you can specify in the `.env` file like this : 53 | 54 | ``` 55 | # Use a minimal log template 56 | TELEGRAM_LOGGER_TEMPLATE = laravel-telegram-logging::minimal 57 | 58 | # Or use the backward compatible one (default setting used even without inserting this row) 59 | TELEGRAM_LOGGER_TEMPLATE = laravel-telegram-logging::standard 60 | ``` 61 | 62 | It is possible to create other blade templates and reference them in the `TELEGRAM_LOGGER_TEMPLATE` entry 63 | 64 | ## Create bot 65 | 66 | For using this package you need to create Telegram bot 67 | 68 | 1. Go to @BotFather in the Telegram 69 | 2. Send ``/newbot`` 70 | 3. Set up name and bot-name for your bot. 71 | 4. Get token and add it to your .env file (it is written above) 72 | 5. Go to your bot and send ``/start`` message 73 | 74 | ## Change log template at runtime 75 | 76 | 1. Change config for template. 77 | ```php 78 | config(['telegram-logger.template'=>'laravel-telegram-logging::custom']) 79 | ``` 80 | 2. Use `Log` as usual. 81 | 82 | ## Configuring a different chat id or token per channel 83 | 84 | 1. Add `chat_id` or `token` to channels in `config/logging.php`. Overrides `config('telegram.chat_id')`. 85 | ```php 86 | [ 87 | 'channels' => [ 88 | [ 89 | 'company' => [ 90 | 'driver' => 'custom', 91 | 'via' => TelegramLogger::class, 92 | 'chat_id' => env('TELEGRAM_COMPANY_CHAT_ID'), 93 | 'token' => env('TELEGRAM_COMPANY_BOT_TOKEN'), 94 | 'level' => 'debug' 95 | ], 96 | 97 | 'operations' => [ 98 | 'driver' => 'custom', 99 | 'via' => TelegramLogger::class, 100 | 'chat_id' => env('TELEGRAM_OPERATIONS_CHAT_ID'), 101 | 'token' => env('TELEGRAM_OPERATIONS_BOT_TOKEN'), 102 | 'level' => 'debug' 103 | ] 104 | ] 105 | ] 106 | ] 107 | ``` 108 | 109 | 2. Use `Log` as usual. 110 | ## Lumen support 111 | 112 | To make it work with Lumen, you need also run two steps: 113 | 114 | 1. Place config/telegram-logger.php file with following code: 115 | ```php 116 | env('TELEGRAM_LOGGER_BOT_TOKEN'), 121 | 122 | // Telegram chat id 123 | 'chat_id' => env('TELEGRAM_LOGGER_CHAT_ID'), 124 | 125 | // you can define your custom template for message 126 | // e.g: logging.template 127 | // 'template' => 'some your view path' 128 | ]; 129 | ``` 130 | 131 | 2. Uncomment ```$app->withFacades();``` and configure the file ```$app->configure('telegram-logger');``` at bootstrap/app.php 132 | 3. Place default Laravel/Lumen logging file to config/logging.php (to add new channel). 133 | 134 | ## Proxy support 135 | To use a proxy server, set the variable in the .env 136 | ``` 137 | TELEGRAM_LOGGER_PROXY=proxy_server.com:port 138 | ``` -------------------------------------------------------------------------------- /src/TelegramHandler.php: -------------------------------------------------------------------------------- 1 | config = $config; 73 | $this->botToken = $this->getConfigValue('token'); 74 | $this->chatId = $this->getConfigValue('chat_id'); 75 | $this->messageThreadId = $this->getConfigValue('message_thread_id'); 76 | 77 | // define variables for text message 78 | $this->appName = config('app.name'); 79 | $this->appEnv = config('app.env'); 80 | } 81 | 82 | /** 83 | * @param array $record 84 | */ 85 | public function write($record): void 86 | { 87 | if (!$this->botToken || !$this->chatId) { 88 | throw new \InvalidArgumentException('Bot token or chat id is not defined for Telegram logger'); 89 | } 90 | 91 | // trying to make request and send notification 92 | try { 93 | $textChunks = str_split($this->formatText($record), 4096); 94 | 95 | foreach ($textChunks as $textChunk) { 96 | $this->sendMessage($textChunk); 97 | } 98 | } catch (Exception $exception) { 99 | \Log::channel('single')->error($exception->getMessage()); 100 | } 101 | } 102 | 103 | /** 104 | * {@inheritDoc} 105 | */ 106 | protected function getDefaultFormatter(): FormatterInterface 107 | { 108 | return new LineFormatter("%message% %context% %extra%\n", null, false, true); 109 | } 110 | 111 | /** 112 | * @param $record 113 | * @return string 114 | */ 115 | private function formatText($record): string 116 | { 117 | if ($template = config('telegram-logger.template')) { 118 | if ($record instanceof LogRecord) { 119 | return view($template, array_merge($record->toArray(), [ 120 | 'appName' => $this->appName, 121 | 'appEnv' => $this->appEnv, 122 | 'formatted' => $record->formatted, 123 | ]) 124 | )->render(); 125 | } 126 | 127 | return view($template, array_merge($record, [ 128 | 'appName' => $this->appName, 129 | 'appEnv' => $this->appEnv, 130 | ]) 131 | )->render(); 132 | } 133 | 134 | return sprintf("%s (%s)\n%s", $this->appName, $record['level_name'], $record['formatted']); 135 | } 136 | 137 | /** 138 | * @param string $text 139 | */ 140 | private function sendMessage(string $text): void 141 | { 142 | $httpQuery = http_build_query(array_merge( 143 | [ 144 | 'text' => $text, 145 | 'chat_id' => $this->chatId, 146 | 'message_thread_id' => $this->messageThreadId, 147 | 'parse_mode' => 'html', 148 | ], 149 | config('telegram-logger.options', []) 150 | )); 151 | 152 | $host = $this->getConfigValue('api_host'); 153 | 154 | $url = $host . '/bot' . $this->botToken . '/sendMessage?' . $httpQuery; 155 | 156 | $proxy = $this->getConfigValue('proxy'); 157 | 158 | if (!empty($proxy)) { 159 | $context = stream_context_create([ 160 | 'http' => [ 161 | 'proxy' => $proxy, 162 | ], 163 | ]); 164 | file_get_contents($url, false, $context); 165 | } else { 166 | file_get_contents($url); 167 | } 168 | } 169 | 170 | /** 171 | * @param string $key 172 | * @param string $defaultConfigKey 173 | * @return string 174 | */ 175 | private function getConfigValue($key, $defaultConfigKey = null): ?string 176 | { 177 | if (isset($this->config[$key])) { 178 | return $this->config[$key]; 179 | } 180 | 181 | return config($defaultConfigKey ?: "telegram-logger.$key"); 182 | } 183 | } 184 | --------------------------------------------------------------------------------