marekmiklusek / telegram-logger
Send Laravel logs and exceptions to Telegram, with flood protection and redaction of sensitive context.
Requires
- php: ^8.2
- laravel/framework: ^12.17.0|^13.0
README
๐ข Laravel Telegram Logger
๐ Laravel Telegram Logger is a package that sends Laravel log messages and exceptions to Telegram for real-time monitoring.
๐ Features
โ
Real-time logging to Telegram
โ
Supports all log levels (debug, info, warning, error, etc.)
โ
Automatic exception handling (captures error file, line, and message)
โ
Configurable log level filtering
โ
Silent notifications support (to avoid sound/vibration in Telegram)
โ
Minimal setup, easy to integrate
โ
Can be enabled/disabled via configuration
๐ Requirements
- PHP 8.4+
- Laravel 13.0+
allow_url_fopenenabled inphp.ini(the default)
๐ Installation
Require the package via Composer:
composer require marekmiklusek/telegram-logger
๐ง Configuration
Publish the package configuration:
php artisan vendor:publish --tag=telegram-logger-config
This will create a config file at config/telegram-logger.php.
.env Configuration
Add your Telegram Bot API token and Chat ID to your .env file:
TELEGRAM_BOT_TOKEN=your_bot_token TELEGRAM_CHAT_ID=your_chat_id
All other options are configurable via .env as well:
TELEGRAM_LOG_LEVEL=error TELEGRAM_LOG_SILENT=false TELEGRAM_LOG_ENABLED=true TELEGRAM_LOG_THROW_ON_FAILURE=false TELEGRAM_LOG_MAX_PER_MINUTE=20 TELEGRAM_LOG_DEDUPE_SECONDS=60
Config File (config/telegram-logger.php)
return [ 'bot_token' => (string) env('TELEGRAM_BOT_TOKEN', ''), 'chat_id' => (string) env('TELEGRAM_CHAT_ID', ''), 'level' => (string) env('TELEGRAM_LOG_LEVEL', 'error'), 'silent_notification' => (bool) env('TELEGRAM_LOG_SILENT', false), 'is_enabled' => (bool) env('TELEGRAM_LOG_ENABLED', true), 'throw_on_failure' => (bool) env('TELEGRAM_LOG_THROW_ON_FAILURE', false), 'api_url' => (string) env('TELEGRAM_LOG_API_URL', 'https://api.telegram.org'), 'max_per_minute' => (int) env('TELEGRAM_LOG_MAX_PER_MINUTE', 20), 'dedupe_seconds' => (int) env('TELEGRAM_LOG_DEDUPE_SECONDS', 60), 'redact_keys' => ['password', 'secret', 'token', 'authorization', 'api_key', 'apikey', 'credit_card', 'cvv'], ];
๐ Usage
Basic Logging
Use Laravel's Log facade as usual, and errors will be sent to Telegram automatically:
use Illuminate\Support\Facades\Log; Log::debug('Debug message'); Log::info('Info message'); Log::warning('Warning message'); Log::error('Error message');
Logging with Context
You can pass additional context to logs:
Log::error('User not found', ['user_id' => 42, 'action' => 'login']);
Logging Exceptions
Exceptions are automatically detected and logged:
try { throw new \Exception('Database connection failed!'); } catch (\Exception $exception) { Log::error('Unhandled exception occurred', ['exception' => $exception]); }
โ How It Works
The package listens to Laravel's logging events and sends structured messages to Telegram.
Example Telegram Log Output
๐ ๏ธ Application: MyLaravelApp
๐ Environment: production
โ Level: ERROR
๐ Message: User not found
๐ File:
/var/www/html/app/Http/Controllers/UserController.php
๐ฏ Line: 45
๐ Context:
{
"user_id": 42,
"action": "login"
}
โณ Time: 2025-02-19 10:15:30
Example Telegram Log Output (Exception)
๐ ๏ธ Application: MyLaravelApp
๐ Environment: production
โ Level: ERROR
๐ Message: Unhandled exception occurred
๐ฅ Exception: PDOException
๐ฅ Message: Database connection failed!
๐ File:
/var/www/html/app/Services/DatabaseService.php
๐ฏ Line: 30
โณ Time: 2025-02-19 10:18:45
๐ฏ Advanced Configuration
1๏ธโฃ Logger Enablement
You can enable or disable the logger in config/telegram-logger.php:
return [ 'is_enabled' => false, ];
โ
If true, logs will be sent to Telegram as configured
โ
If false, the logger will be completely disabled (no logs sent)
2๏ธโฃ Log Level Filtering
You can define the minimum log level in config/telegram-logger.php:
return [ 'level' => 'warning', ];
debug: Logs everythinginfo: Logsinfo,notice,warning,error,critical,alert,emergencyerror: Logserror,critical,alert,emergencycritical: Logs onlycritical,alert,emergency
3๏ธโฃ Silent Notifications
Enable silent notifications (no sound/vibration) in config/telegram-logger.php
return [ 'silent_notification' => true, ];
โ
If true, messages will be sent silently.
โ
If false, Telegram will send notifications normally.
4๏ธโฃ Failure Reporting
By default a failed delivery is swallowed โ a logger must never break the application:
return [ 'throw_on_failure' => false, ];
Set TELEGRAM_LOG_THROW_ON_FAILURE=true locally to surface the actual Telegram API error
(invalid token, chat not found, rate limit) instead of silence.
If Telegram rejects the message formatting (HTTP 400), the package automatically retries once as plain text, so the log is delivered even when formatting fails.
๐ก Troubleshooting
โ Logs not appearing in Telegram?
- Set
TELEGRAM_LOG_THROW_ON_FAILURE=trueโ the real API error will be thrown. - Check that your
.envvalues are correctly set:
php artisan config:clear php artisan config:cache
- Ensure your bot has permission to send messages to your chat.
- Verify
TELEGRAM_LOG_LEVELis not more severe than the level you are logging. - Confirm
allow_url_fopenis enabled โ without it the API cannot be reached and the package throwsTelegram API is unreachable.
โ Behind a proxy?
Point TELEGRAM_LOG_API_URL at your own Bot API endpoint.
โ Getting "Chat not found" error?
- Make sure you have sent a message to your bot first.
- Use this tool to get your Chat ID.
5๏ธโฃ Flood Protection
An error storm must not turn into hundreds of Telegram requests, so two limits apply:
return [ 'dedupe_seconds' => 60, 'max_per_minute' => 20, ];
dedupe_secondssends an identical message only once per windowmax_per_minutecaps how many messages leave the application per minute
Set either to 0 to disable it. Both require a working cache; when no cache is
available they are skipped and logs are delivered as usual.
6๏ธโฃ Redacting Sensitive Data
Context is sent to a third party, so known sensitive keys are replaced with [REDACTED]:
Log::error('Login failed', ['email' => 'a@b.com', 'password' => 'hunter2']);
๐ Context:
{
"email": "a@b.com",
"password": "[REDACTED]"
}
Keys are matched case-insensitively as a substring, so password also covers
password_confirmation. Nested arrays are redacted too. Configure the list via
redact_keys, or set it to [] to disable redaction.
๐งช Testing
composer test
This runs the full quality chain: Pint, Rector, PHPStan (level max), 100% type coverage and the test suite with 100% code coverage.
Individual steps:
composer test:lint # Pint code style check composer test:refactor # Rector dry run composer test:types # PHPStan level max composer test:type-coverage # 100% type coverage composer test:unit # Pest with 100% code coverage
To apply automatic fixes:
composer lint # Pint composer refactor # Rector
๐ Changelog
See CHANGELOG.md for release notes and upgrade instructions.
๐ License
This package is open-source and licensed under the MIT License.