jardiscore / logger
Jardis logger is a very powerful and flexible PHP logging library that allows you to log data in various formats and send it to different destinations such as files, databases, emails, or external services.
Installs: 38
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/jardiscore/logger
Requires
- php: >=8.2
- ext-amqp: *
- ext-json: *
- ext-pdo: *
- ext-rdkafka: *
- ext-redis: *
- jardiscore/dotenv: 1.0.0
- psr/container: ^2.0
- psr/log: ^3.0
Requires (Dev)
- phpstan/phpstan: ^2.0.4
- phpunit/phpunit: ^10.5
- squizlabs/php_codesniffer: ^3.11.2
README
PSR-3 Logger for PHP 8.2+ • Simple Start • Enterprise Scale • Domain-Driven Design
// One line. Done. $logger = (new Logger('MyApp'))->addConsole(LogLevel::INFO); $logger->info('Hello World');
What Makes Jardis Logger Special?
🚀 Productive in Seconds
No config files, no complex setup. Fluent interface with IDE autocomplete for all 20+ handlers.
⚡ Flexibly Scalable
From simple scripts to multi-context enterprise architectures. One logger per bounded context (DDD).
🎯 Production-Ready Features
- 20+ Handlers: File, Console, Slack, Teams, Kafka, RabbitMQ, Redis, Loki, Database, Email, Webhook...
- Smart Handlers: FingersCrossed (buffering), Sampling (volume reduction), Conditional (routing)
- Auto-Enrichment: Timestamps, UUIDs, Memory, IPs automatically added to every log
- Multiple Formats: JSON, Human-Readable, Loki, Slack, Teams, ChromeLogger
- Named Handlers: Dynamic handler management at runtime
- Error Resilience: One handler fails? Others continue processing
🏆 Enterprise-Grade Quality
- PSR-3 v3.0 Compliant - Drop-in replacement with modern PHP 8+ types
- PHPStan Level 8 - Highest static analysis level
- 85.66% Code Coverage - 285 tests, 709 assertions
- PHP 8.2+ Strict Types - Full type safety
Installation
composer require jardis/core-logger
Quick Start
Get Started in 3 Lines
use JardisCore\Logger\Logger; use Psr\Log\LogLevel; $logger = (new Logger('App'))->addConsole(LogLevel::INFO); $logger->info('User {user} logged in', ['user' => 'john.doe']);
Fluent Interface - Chain Handlers
$logger = (new Logger('OrderService')) ->addConsole(LogLevel::DEBUG) // Development: Everything to console ->addFile(LogLevel::INFO, '/var/log/app.log') // Production: INFO+ to file ->addSlack(LogLevel::ERROR, 'https://...') // Alerts: ERROR+ to Slack ->addKafkaMq($producer, 'logs'); // Analytics: Everything to Kafka $logger->debug('Validating order data'); // → Console only $logger->info('Order #12345 created'); // → Console + File + Kafka $logger->error('Payment gateway timeout'); // → ALL handlers
Auto-Enrichment - Automatic Context
$logger = (new Logger('API'))->addFile(LogLevel::INFO, '/var/log/api.log', 'api'); $logger->getHandler('api') ->logData() ->addField('timestamp', new LogDateTime()) // Root-level (for DB columns, indexing) ->addField('request_id', new LogUuid()) // Root-level ->addExtra('memory_mb', new LogMemoryUsage()) // Inside 'data' (business context) ->addExtra('client_ip', new LogClientIp()); // Inside 'data' // Every log now automatically includes: timestamp, request_id, memory_mb, client_ip $logger->info('Request processed', ['endpoint' => '/api/users']);
📚 Complete Examples
We've created 13 progressive examples - from simple to enterprise:
🎓 Getting Started
| Example | Description | Link |
|---|---|---|
| 01 | Quick Start - One-Line Logger | → Code |
| 02 | File Logging + Context Interpolation | → Code |
| 03 | Multiple Handlers with Level Filtering | → Code |
🔧 Advanced Features
| Example | Description | Link |
|---|---|---|
| 04 | Enrichers - Auto-Context (Timestamps, UUIDs, Memory, IP) | → Code |
| 05 | Named Handlers - Dynamic Management | → Code |
| 06 | Formatters - JSON, Human, Line, Loki, Slack | → Code |
| 07 | FingersCrossed - Smart Buffering for Production | → Code |
| 08 | Sampling - Volume Reduction (Percentage, Smart) | → Code |
| 09 | Conditional Routing - Multi-Tenant Ready | → Code |
🏢 Enterprise & Message Queues
| Example | Description | Link |
|---|---|---|
| 10 | DDD Bounded Contexts - Enterprise Architecture | → Code |
| 11 | Redis Pub/Sub - Real-Time Log Streaming | → Code |
| 12 | RabbitMQ (AMQP) - Enterprise Message Queue | → Code |
| 13 | Apache Kafka - High-Throughput Streaming | → Code |
Handler Overview
Basic Handlers (Fluent Methods)
->addConsole(LogLevel::INFO) // STDOUT/STDERR ->addFile(LogLevel::INFO, '/var/log/app.log') // File with rotation support ->addSyslog(LogLevel::WARNING) // System syslog ->addErrorLog(LogLevel::ERROR) // PHP error_log()
Chat & Alerts
->addSlack(LogLevel::ERROR, 'https://hooks.slack.com/...') ->addTeams(LogLevel::CRITICAL, 'https://outlook.office.com/...') ->addEmail(LogLevel::CRITICAL, 'admin@example.com', 'logger@example.com')
Observability
->addLoki(LogLevel::INFO, 'http://loki:3100/...', ['service' => 'api']) ->addStash(LogLevel::INFO, 'logstash.local', 5000) ->addBrowserConsole(LogLevel::DEBUG) // ChromeLogger for DevTools
Message Queues
->addKafkaMq($producer, 'application-logs') ->addRabbitMq($connection, 'logs-exchange') ->addRedisMq($redis, 'logs-channel')
Storage
->addDatabase(LogLevel::INFO, $pdo, 'logs_table') ->addRedis(LogLevel::WARNING, 'localhost', 6379)
Network
->addWebhook(LogLevel::ERROR, 'https://api.example.com/logs', 'webhook', 'POST')
Smart Handlers
// Buffering: Write DEBUG only on ERROR ->addFingersCrossed($handler, LogLevel::ERROR, 100, true) // Sampling: 10% of DEBUG, 100% of ERROR+ ->addSampling($handler, LogSampling::STRATEGY_PERCENTAGE, ['percentage' => 10]) // Routing: Condition-based ->addConditional([ [fn($l, $m, $ctx) => $ctx['admin'] ?? false, $adminHandler], [fn($l, $m, $ctx) => $l === LogLevel::CRITICAL, $alertHandler], ], $defaultHandler)
Enricher Overview
Enrichers are callables that automatically add data to every log:
use JardisCore\Logger\Enricher\{LogDateTime, LogUuid, LogMemoryUsage, LogMemoryPeak, LogClientIp, LogWebRequest}; $handler->logData() ->addField('timestamp', new LogDateTime()) // ISO 8601 ->addField('request_id', new LogUuid()) // UUID v4 ->addExtra('memory_mb', new LogMemoryUsage()) // Current memory ->addExtra('memory_peak_mb', new LogMemoryPeak()) ->addExtra('client_ip', new LogClientIp()) ->addExtra('http_request', new LogWebRequest());
Difference:
addField()→ Root-level (DB columns, indexing, search)addExtra()→ Inside 'data' field (business context, dynamic)
Formatter Overview
Each handler can have its own formatter:
use JardisCore\Logger\Formatter\{LogJsonFormat, LogHumanFormat, LogLineFormat, LogLokiFormat, LogSlackFormat, LogTeamsFormat, LogBrowserConsoleFormat}; $logger->addFile(LogLevel::INFO, '/var/log/app.log', 'json', new LogJsonFormat()); $logger->addConsole(LogLevel::DEBUG, 'console', new LogHumanFormat());
LogJsonFormat- Structured JSON for ELK, SplunkLogHumanFormat- Multi-line, readable for consoleLogLineFormat- Compact, single-lineLogLokiFormat- Grafana Loki with labelsLogSlackFormat- Slack Block KitLogTeamsFormat- Microsoft Teams MessageCardLogBrowserConsoleFormat- ChromeLogger Protocol
Production Features
Named Handler Management
$logger->addFile(LogLevel::INFO, '/tmp/app.log', 'app_log'); $logger->addFile(LogLevel::ERROR, '/tmp/error.log', 'error_log'); // Retrieve by name $handler = $logger->getHandler('app_log'); // Remove by name $logger->removeHandler('error_log'); // Get all handlers of type $fileHandlers = $logger->getHandlersByClass(LogFile::class); // Get all handlers $allHandlers = $logger->getHandlers();
Error Handling
$logger->setErrorHandler(function (\Throwable $e, string $handlerId, string $level, string $message, array $context) { error_log("Handler {$handlerId} failed: {$e->getMessage()}"); // Logger continues with other handlers });
DDD Architecture Pattern
// Each bounded context has its own logger class OrderContext { private Logger $logger; public function __construct() { $this->logger = (new Logger('OrderContext')) ->addFile(LogLevel::INFO, '/var/log/orders.log') ->addKafkaMq($producer, 'order-events'); } } class PaymentContext { private Logger $logger; public function __construct() { $this->logger = (new Logger('PaymentContext')) ->addFile(LogLevel::DEBUG, '/var/log/payments.log') ->addSlack(LogLevel::CRITICAL, 'https://...'); } }
Development
# Start Docker services (Redis, Kafka, RabbitMQ, MailHog, WireMock) make start # Run all tests make phpunit # Coverage report make phpunit-coverage-html # Static analysis make phpstan # Code style check make phpcs # Stop services make stop
Test Statistics:
- 285 Tests, 709 Assertions
- 85.66% Line Coverage, 75.90% Method Coverage
- Unit + Integration Tests
- PHPStan Level 8, PSR-12
Requirements
- PHP 8.2+ (Strict Types)
- PSR-3 v3.0 (psr/log ^3.0)
- Optional Extensions: ext-redis, ext-amqp, ext-rdkafka (only for specific handlers)
License
MIT License - Free to use in commercial and open-source projects.
Made with ❤️ for modern PHP applications.