neuron-php / logging
Logging.
Requires
- php: ^8.4
- ext-curl: *
- ext-json: *
- ext-sockets: *
- neuron-php/core: 0.8.*
- neuron-php/patterns: ^0.7.2
- neuron-php/util: 0.6.*
- neuron-php/validation: 0.7.*
Requires (Dev)
- php-mock/php-mock-phpunit: ^2.10
- phpmd/phpmd: ^2.15
- phpunit/phpunit: ^13.4
Suggests
- aws/aws-sdk-php: ^3.0 - Required for Amazon SQS destination
- psr/log: ^3.0 - Required for PSR-3 adapter functionality
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-30 22:49:04 UTC
README
Neuron-PHP Logging
A flexible and powerful logging component for PHP 8.4+ applications, part of the Neuron-PHP framework.
Features
- PSR-3 Compatible: Full PSR-3 logger interface with array contexts and message interpolation
- Multiple Destinations: Write logs to files, console, Slack, webhooks, syslog, Nightwatch, and more
- Flexible Formatting: Support for plain text, JSON, HTML, CSV, and custom formats
- Log Levels: Full PSR-3 compliant log levels (debug, info, notice, warning, error, critical, alert, emergency)
- Array Context Support: Pass complex arrays, objects, and exceptions as context
- Message Interpolation: Use
{placeholders}in messages for automatic substitution - Channels: Manage multiple independent loggers with automatic channel tracking
- Filters: Apply custom filters to control which logs are written
- Multiplexing: Write to multiple destinations simultaneously with different run levels
- Exception Tracking: Automatic exception formatting with stack traces
- Laravel Nightwatch: Forward logs into Laravel's existing
nightwatchchannel
Requirements
- PHP 8.4 or higher
- ext-curl (for webhook/Slack destinations)
- ext-json (for JSON formatting)
- ext-sockets (for socket destination)
Installation
Install via Composer:
composer require neuron-php/logging
Quick Start
The simplest way to start logging is using the singleton facade:
use Neuron\Log\Log; // Set the minimum log level Log::setRunLevel( 'debug' ); // Write log messages Log::debug( 'Debug message' ); Log::info( 'Information message' ); Log::notice( 'Notice: user registration started' ); Log::warning( 'Warning message' ); Log::error( 'Error message' ); Log::critical( 'Critical: database connection lost' ); Log::alert( 'Alert: disk space critically low' ); Log::emergency( 'Emergency: system is shutting down' ); // With array context and interpolation (PSR-3 style) Log::error( 'User {userId} failed login from {ip}', [ 'userId' => 12345, 'ip' => '192.168.1.1', 'attempts' => 3 ] );
Destinations
The logging component supports writing to various destinations:
Available Destinations
- Echo: Output to browser/console
- Email: Send logs via email
- File: Write to log files
- Memory: Store logs in memory for testing
- Nightwatch: Forward logs to Laravel's Nightwatch channel
- Null: Discard logs (useful for testing)
- Papertrail: Send to Papertrail cloud logging service
- Slack: Post to Slack channels
- Socket: Send over network sockets
- Sqs: Send to Amazon SQS for queue-based processing
- StdErr: Write to standard error
- StdOut: Write to standard output
- StdOutStdErr: Write to both stdout and stderr based on level
- SysLog: System logging
- Webhook: Send to custom webhooks
- WebSocket: Stream logs in real-time via WebSocket
Formats
Each destination can use different formatting:
- CSV: Comma-separated values
- HTML: HTML formatted output
- HTMLEmail: HTML optimized for emails
- JSON: Structured JSON output
- PlainText: Human-readable text format
- Raw: Unformatted output
- Slack: Slack-specific formatting
Usage Examples
Basic Logging
use Neuron\Log\Log; // Configure run level Log::setRunLevel( 'debug' ); // Simple logging Log::debug( 'Debug information' ); Log::info( 'Application started' ); Log::warning( 'Memory usage high' ); // With array context Log::error( 'Database connection failed', [ 'host' => 'db.example.com', 'port' => 3306, 'error' => 'Connection timeout' ] ); // With message interpolation Log::info( 'User {user} performed {action}', [ 'user' => 'admin@example.com', 'action' => 'delete_records', 'count' => 42 ] );
File Logging
use Neuron\Log\Logger; use Neuron\Log\Destination\File; use Neuron\Log\Format\PlainText; // Create a file logger $fileDestination = new File( new PlainText() ); $fileDestination->open( [ 'path' => '/var/log/app.log' ] ); $logger = new Logger( $fileDestination ); $logger->setRunLevel( 'info' ); $logger->info( 'Application event logged to file' );
JSON Logging
use Neuron\Log\Logger; use Neuron\Log\Destination\File; use Neuron\Log\Format\JSON; // Log in JSON format for structured logging $jsonDestination = new File( new JSON() ); $jsonDestination->open( [ 'path' => '/var/log/app.json' ] ); $jsonLogger = new Logger( $jsonDestination ); // Array context is automatically included in JSON output $jsonLogger->error( 'Database error', [ 'query' => 'SELECT * FROM users', 'error_code' => 1054, 'duration' => 234.5 ] );
Slack Integration
use Neuron\Log\Log; use Neuron\Log\Logger; use Neuron\Log\Destination\Slack; use Neuron\Log\Format\SlackFormat; $slack = new Slack( new SlackFormat() ); $slack->open( [ 'endpoint' => $_ENV['LOG_SLACK_WEBHOOK_URL'], 'params' => [ 'channel' => '#alerts', 'username' => 'AppLogger', 'icon_emoji' => ':warning:' ] ] ); $slackLogger = new Logger( $slack ); $slackLogger->setRunLevel( 'error' ); // Add to the multiplexer Log::getInstance()->Logger->addLog( $slackLogger ); // Now errors and above will also go to Slack with context Log::error( 'Payment processing failed', [ 'transaction_id' => 'txn_12345', 'amount' => 99.99, 'currency' => 'USD' ] );
Laravel Nightwatch Integration
Use this when the Laravel application already runs Nightwatch. The destination forwards each Neuron record to Laravel's nightwatch log channel. Nightwatch's handler attaches the current request or job, and the local agent delivers it. There is no Nightwatch HTTP API to call, and no Nightwatch-specific formatter.
Pass the nightwatch channel. Do not pass stack or the default channel. If that default driver writes back into Neuron, a stack write recurses.
use Neuron\Log\Log; use Neuron\Log\Logger; use Neuron\Log\Destination\Nightwatch; use Neuron\Log\Format\Raw; use Illuminate\Support\Facades\Log as LaravelLog; $destination = new Nightwatch( new Raw() ); $destination->open( [ 'logger' => LaravelLog::channel( 'nightwatch' ) ] ); $nightwatchLogger = new Logger( $destination ); $nightwatchLogger->setRunLevel( 'info' ); Log::getInstance()->logger->addLog( $nightwatchLogger ); Log::info( 'User logged in', [ 'user_id' => 123 ] ); Log::error( 'Payment processing failed', [ 'transaction_id' => 'txn_abc123', 'exception' => $exception ] );
Keep the Laravel setup you already have: LOG_STACK=single,nightwatch, the Nightwatch agent, and NIGHTWATCH_TOKEN.
Context is forwarded as given. Leave exception as a Throwable so Nightwatch can serialize it. user, request, and any other keys stay in the context array.
Channels
The Neuron channel name is copied into context under neuron_channel. Override that key with channel_key when calling open(). Laravel's Monolog channel name remains nightwatch. A logger stores one channel name, so give each Neuron channel its own logger:
$laravel = LaravelLog::channel( 'nightwatch' ); $audit = new Logger( new Nightwatch( new Raw() ) ); $audit->open( [ 'logger' => $laravel ] ); $audit->setRunLevel( 'info' ); Log::addChannel( 'audit', $audit ); Log::channel( 'audit' )->info( 'User updated profile', [ 'user_id' => 123 ] ); // Context includes neuron_channel=audit
Papertrail Integration
Papertrail is a cloud-based logging service that aggregates and centralizes logs from multiple sources. The Papertrail destination sends logs using the remote syslog protocol with optional TLS encryption.
use Neuron\Log\Logger; use Neuron\Log\Destination\Papertrail; use Neuron\Log\Format\PlainText; // Create Papertrail destination $papertrail = new Papertrail( new PlainText() ); $papertrail->open( [ 'host' => 'logs5.papertrailapp.com', // Your Papertrail host 'port' => 12345, // Your Papertrail port 'system_name' => 'my-app-prod', // Optional: System name (defaults to hostname) 'use_tls' => true, // Optional: Use TLS encryption (default: true) 'facility' => 16, // Optional: Syslog facility (default: 16 for local0) 'sd_id' => 'mycompany@12345' // Optional: Structured Data ID (default: 'neuron@32473') ] ); $papertrailLogger = new Logger( $papertrail ); $papertrailLogger->setRunLevel( 'info' ); // Logs are sent to Papertrail with structured data $papertrailLogger->error( 'Payment processing failed', [ 'transaction_id' => 'txn_12345', 'amount' => 99.99, 'currency' => 'USD', 'error_code' => 'INSUFFICIENT_FUNDS' ] ); // Context is included as structured data in syslog format $papertrailLogger->info( 'User action', [ 'user_id' => 456, 'action' => 'purchase', 'items' => [ 'SKU-123', 'SKU-456' ] ] );
The Papertrail destination:
- Sends logs using RFC 5424 syslog format over TCP/TLS
- Automatically maps log levels to syslog severities
- Includes context as structured data for easy filtering in Papertrail
- Supports automatic reconnection if the connection is lost
- Allows custom SD-ID for organizations with IANA Private Enterprise Numbers
Amazon SQS Integration
Send logs to Amazon SQS for scalable, queue-based processing:
use Neuron\Log\Logger; use Neuron\Log\Destination\Sqs; use Neuron\Log\Format\JSON; // Create SQS destination $sqs = new Sqs( new JSON() ); $sqs->open( [ 'queue_url' => 'https://sqs.us-east-1.amazonaws.com/123456789/my-log-queue', 'region' => 'us-east-1', 'credentials' => [ // Optional: Use IAM role if not provided 'key' => $_ENV['AWS_ACCESS_KEY'], 'secret' => $_ENV['AWS_SECRET_KEY'] ], 'batch_size' => 10, // Optional: Batch messages (1-10, default 1) 'attributes' => [ // Optional: Message attributes 'Environment' => 'production', 'Application' => 'neuron-app' ], 'max_retries' => 3, // Optional: Retry attempts (default 3) 'retry_delay' => 1.0 // Optional: Initial retry delay in seconds ] ); $sqsLogger = new Logger( $sqs ); $sqsLogger->setRunLevel( 'info' ); // Logs are sent to SQS with automatic batching $sqsLogger->error( 'Critical system error', [ 'service' => 'payment-processor', 'error_code' => 'GATEWAY_TIMEOUT', 'retry_count' => 3 ] ); // Context and channel are included in message body $sqsLogger->info( 'Order processed', [ 'order_id' => 'ORD-12345', 'amount' => 299.99, 'items' => 5 ] );
The SQS destination:
- Sends logs as JSON messages to SQS queues
- Supports batching up to 10 messages for improved performance
- Automatic retry with exponential backoff
- Message attributes for filtering and routing
- Works with IAM roles or explicit credentials
- Includes log level and channel as message attributes
Required: Install the AWS SDK via Composer:
composer require aws/aws-sdk-php
WebSocket Real-Time Streaming
Stream logs in real-time to web browsers or monitoring dashboards using WebSocket connections:
use Neuron\Log\Logger; use Neuron\Log\Destination\WebSocket; use Neuron\Log\Format\JSON; // Create WebSocket destination $websocket = new WebSocket( new JSON() ); $websocket->open( [ 'url' => 'ws://localhost:8080/logs', // WebSocket server URL 'max_reconnect_attempts' => 5, // Optional: Max reconnection attempts (default: 5) 'reconnect_delay' => 1.0 // Optional: Initial reconnect delay in seconds ] ); $wsLogger = new Logger( $websocket ); $wsLogger->setRunLevel( 'debug' ); // Logs are streamed in real-time to connected WebSocket clients $wsLogger->info( 'Real-time event', [ 'event_type' => 'user_login', 'user_id' => 123, 'timestamp' => time() ] );
The WebSocket destination:
- Maintains persistent WebSocket connections
- Automatically reconnects with exponential backoff
- Sends logs as WebSocket text frames
- Perfect for real-time monitoring dashboards
- Works with any WebSocket server implementation
Array Context Support (PSR-3 Compatible)
use Neuron\Log\Log; // Pass array context as second parameter Log::error( 'Database query failed', [ 'query' => 'SELECT * FROM orders WHERE id = ?', 'params' => [12345], 'duration' => 1234.5, 'error' => 'Connection timeout' ] ); // Complex nested arrays Log::info( 'Order processed', [ 'order' => [ 'id' => 'ORD-12345', 'items' => [ [ 'sku' => 'WIDGET-1', 'qty' => 2 ], [ 'sku' => 'GADGET-5', 'qty' => 1 ] ], 'total' => 149.99 ], 'customer_id' => 789 ] ); // Exception tracking with automatic formatting try { // some operation } catch( Exception $e ) { Log::error( 'Operation failed', [ 'exception' => $e, // Stack trace automatically captured 'operation' => 'process_payment', 'user_id' => $userId ] ); }
Message Interpolation
// Use {placeholders} in messages - PSR-3 style Log::info( 'User {userId} logged in from {ip} at {time}', [ 'userId' => 12345, 'ip' => '192.168.1.100', 'time' => date( 'H:i:s' ) ] ); // Output: User 12345 logged in from 192.168.1.100 at 14:30:45 // Interpolation works with all log levels Log::error( 'Failed to send email to {email}: {error}', [ 'email' => 'user@example.com', 'error' => 'SMTP connection refused', 'retry_count' => 3 ] );
Global and Local Context
use Neuron\Log\Log; // Set global context that applies to all logs Log::setContext( 'app_version', '2.0.0' ); Log::setContext( 'environment', 'production' ); Log::setContext( 'server', gethostname() ); // Can also set array values in global context Log::setContext( 'tags', [ 'monitoring', 'production' ] ); // Local context in log call is merged with global Log::info( 'User action', [ 'action' => 'profile_update', 'user_id' => 456 ] ); // Both global and local context are included ### Multiple Channels ```php use Neuron\Log\Log; use Neuron\Log\Logger; use Neuron\Log\Destination\File; use Neuron\Log\Destination\Slack; use Neuron\Log\Format\PlainText; use Neuron\Log\Format\SlackFormat; // Create an audit logger $auditFile = new File( new PlainText() ); $auditFile->open( [ 'path' => '/var/log/audit.log' ] ); $auditLogger = new Logger( $auditFile ); // Create a real-time alerts logger $alertSlack = new Slack( new SlackFormat() ); $alertSlack->open( [ 'endpoint' => $_ENV['SLACK_WEBHOOK'], 'params' => [ 'channel' => '#alerts' ] ] ); $alertLogger = new Logger( $alertSlack ); // Register channels Log::addChannel( 'audit', $auditLogger ); Log::addChannel( 'alerts', $alertLogger ); // Use specific channels Log::channel( 'audit' )->info( 'User login', [ 'user' => $username ] ); Log::channel( 'alerts' )->emergency( 'System down!' );
Multiplexer (Multiple Destinations)
use Neuron\Log\LogMux; use Neuron\Log\Logger; use Neuron\Log\Destination\File; use Neuron\Log\Destination\StdErr; use Neuron\Log\Format\PlainText; use Neuron\Log\Format\JSON; // Create multiple loggers $fileLogger = new Logger( new File( new JSON() ) ); $fileLogger->getDestination()->open( [ 'path' => '/var/log/app.json' ] ); $fileLogger->setRunLevel( 'debug' ); $consoleLogger = new Logger( new StdErr( new PlainText() ) ); $consoleLogger->setRunLevel( 'warning' ); // Create multiplexer $mux = new LogMux(); $mux->addLog( $fileLogger ); $mux->addLog( $consoleLogger ); // Logs go to both destinations based on their run levels $mux->debug( 'Debug info' ); // Only to file $mux->warning( 'Warning!' ); // To both file and console $mux->error( 'Error occurred' ); // To both file and console
PSR-3 Adapter
The Neuron logging component provides a PSR-3 adapter that allows you to use Neuron loggers with any library or framework that expects a PSR-3 compliant logger (like Symfony, Laravel packages, Monolog alternatives, etc.).
Basic Usage
use Neuron\Log\Logger; use Neuron\Log\Adapter\Psr3Adapter; use Neuron\Log\Destination\File; use Neuron\Log\Format\JSON; // Create a Neuron logger $destination = new File( new JSON() ); $destination->open( [ 'path' => '/var/log/app.json' ] ); $neuronLogger = new Logger( $destination ); $neuronLogger->setRunLevel( 'info' ); // Wrap it with the PSR-3 adapter $psr3Logger = new Psr3Adapter( $neuronLogger ); // Now use it with any PSR-3 expecting code $psr3Logger->info( 'Application started' ); $psr3Logger->error( 'Database connection failed', [ 'host' => 'db.example.com', 'error' => 'Connection timeout' ] );
Framework Integration
The adapter makes it easy to integrate Neuron logging into frameworks that expect PSR-3:
use Neuron\Log\Log; use Neuron\Log\Adapter\Psr3Adapter; // Get Neuron's singleton logger and wrap it $psr3Logger = new Psr3Adapter( Log::getInstance()->Logger ); // Use with Symfony components $httpClient = new \Symfony\Component\HttpClient\CurlHttpClient( [ 'logger' => $psr3Logger ] ); // Use with Guzzle $guzzleClient = new \GuzzleHttp\Client( [ 'handler' => $handlerStack, 'logger' => $psr3Logger ] ); // Use with any PSR-3 compatible library $thirdPartyService = new ThirdPartyService( $psr3Logger );
Level Mapping
The adapter automatically maps PSR-3 log levels to Neuron's RunLevel enum:
| PSR-3 Level | Neuron RunLevel | Numeric Value |
|---|---|---|
| emergency | EMERGENCY | 50 |
| alert | ALERT | 45 |
| critical | CRITICAL | 40 |
| error | ERROR | 30 |
| warning | WARNING | 20 |
| notice | NOTICE | 15 |
| info | INFO | 10 |
| debug | DEBUG | 0 |
Advanced Features
The adapter maintains full compatibility with Neuron's advanced features:
use Neuron\Log\Logger; use Neuron\Log\Adapter\Psr3Adapter; use Neuron\Log\Destination\File; use Neuron\Log\Format\JSON; // Create Neuron logger with multiple destinations $fileLogger = new Logger( new File( new JSON() ) ); $fileLogger->getDestination()->open( [ 'path' => '/var/log/app.json' ] ); // Add filters, context, and other Neuron features $fileLogger->setContext( 'app_version', '2.0.0' ); $fileLogger->setContext( 'environment', 'production' ); // Wrap with PSR-3 adapter $psr3Logger = new Psr3Adapter( $fileLogger ); // PSR-3 calls use Neuron features underneath $psr3Logger->warning( 'API rate limit approaching', [ 'requests' => 950, 'limit' => 1000 ] ); // Context includes: app_version, environment, requests, limit // Access the underlying Neuron logger if needed $neuronLogger = $psr3Logger->getNeuronLogger(); $neuronLogger->setRunLevel( 'debug' );
Why Use the Adapter?
- Framework Integration: Use Neuron's powerful logging with any PSR-3 expecting library
- Gradual Migration: Migrate from other PSR-3 loggers without changing application code
- Best of Both Worlds: Keep Neuron's advanced features (multiple destinations, formats, filters) while maintaining PSR-3 compatibility
- Drop-in Replacement: Works as a drop-in replacement for Monolog, PSR-3 Log, or other PSR-3 implementations
Custom Filters
use Neuron\Log\Logger; use Neuron\Log\Filter\IFilter; use Neuron\Log\RunLevel; class ProductionFilter implements IFilter { public function shouldLog( RunLevel $level, string $message, array $context ): bool { // Don't log debug messages in production if( $level === RunLevel::DEBUG && $_ENV['APP_ENV'] === 'production' ) { return false; } // Don't log sensitive data if( str_contains( $message, 'password' ) || str_contains( $message, 'token' ) ) { return false; } return true; } } $logger = new Logger( $destination ); $logger->addFilter( new ProductionFilter() );
Advanced Configuration
Environment-Based Configuration
use Neuron\Log\Log; use Neuron\Log\Logger; use Neuron\Log\Destination\File; use Neuron\Log\Destination\StdOut; use Neuron\Log\Format\JSON; use Neuron\Log\Format\PlainText; $environment = $_ENV['APP_ENV'] ?? 'development'; if( $environment === 'production' ) { // Production: JSON to file $destination = new File( new JSON() ); $destination->open( [ 'path' => '/var/log/app.json' ] ); $runLevel = 'warning'; } else { // Development: Plain text to console $destination = new StdOut( new PlainText( true ) ); $runLevel = 'debug'; } $logger = new Logger( $destination ); $logger->setRunLevel( $runLevel ); Log::getInstance()->Logger->addLog( $logger );
Testing with Memory Logger
use Neuron\Log\Logger; use Neuron\Log\Destination\Memory; use Neuron\Log\Format\Raw; // For unit testing $memoryDestination = new Memory( new Raw() ); $testLogger = new Logger( $memoryDestination ); $testLogger->error( 'Test error' ); $testLogger->info( 'Test info' ); // Retrieve logged messages $logs = $memoryDestination->getLogs(); assert( count( $logs ) === 2 ); assert( $logs[0]['level'] === 'error' );
API Reference
Log Levels
The following PSR-3 compliant log levels are supported (from lowest to highest severity):
debug(0) - Detailed debug information for development and troubleshootinginfo(10) - Informational messages about application flownotice(15) - Normal but significant eventswarning(20) - Warning messages about potentially harmful situationserror(30) - Error events that allow the application to continue runningcritical(40) - Critical conditions that need immediate attentionalert(45) - Action must be taken immediatelyemergency(50) - System is unusable, requires immediate intervention
Logger Methods
All logger methods accept an optional array context for additional data:
$logger->debug( string $message, array $context = [] ); $logger->info( string $message, array $context = [] ); $logger->notice( string $message, array $context = [] ); $logger->warning( string $message, array $context = [] ); $logger->error( string $message, array $context = [] ); $logger->critical( string $message, array $context = [] ); $logger->alert( string $message, array $context = [] ); $logger->emergency( string $message, array $context = [] ); $logger->log( string $message, RunLevel $level, array $context = [] ); // Set minimum log level $logger->setRunLevel( mixed $level ); // Accepts RunLevel enum or string $logger->setRunLevelText( string $level ); // Set by text: 'debug', 'info', etc. $logger->getRunLevel(): RunLevel; // Get current run level // Context management $logger->setContext( string $name, mixed $value ); // Add global context $logger->getContext(): array; // Get all context $logger->reset(); // Clear all context
Testing
Run the test suite:
./vendor/bin/phpunit tests
Run tests with coverage:
./vendor/bin/phpunit tests --coverage-text
Contributing
Contributions are welcome! Please ensure all tests pass and maintain code coverage above 95%.
License
MIT License - see LICENSE file for details.
More Information
- Full documentation: neuronphp.com
- GitHub: github.com/neuron-php/logging
- Issues: github.com/neuron-php/logging/issues