Skip to content

Repository files navigation

CIcodecov

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: Full integration with special context handling

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:

useNeuron\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: Send to Laravel Nightwatch monitoring service
  • 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
  • Nightwatch: Laravel Nightwatch-specific JSON formatting
  • PlainText: Human-readable text format
  • Raw: Unformatted output
  • Slack: Slack-specific formatting

Usage Examples

Basic Logging

useNeuron\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

useNeuron\Log\Logger;
useNeuron\Log\Destination\File;
useNeuron\Log\Format\PlainText;
// Create a file logger$fileDestination = newFile( newPlainText() );
$fileDestination->open( [ 'path' => '/var/log/app.log' ] );
$logger = newLogger( $fileDestination );
$logger->setRunLevel( 'info' );
$logger->info( 'Application event logged to file' );

JSON Logging

useNeuron\Log\Logger;
useNeuron\Log\Destination\File;
useNeuron\Log\Format\JSON;
// Log in JSON format for structured logging$jsonDestination = newFile( newJSON() );
$jsonDestination->open( [ 'path' => '/var/log/app.json' ] );
$jsonLogger = newLogger( $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

useNeuron\Log\Log;
useNeuron\Log\Logger;
useNeuron\Log\Destination\Slack;
useNeuron\Log\Format\SlackFormat;
$slack = newSlack( newSlackFormat() );
$slack->open( [
'endpoint' => $_ENV['LOG_SLACK_WEBHOOK_URL'],
'params' => [
'channel' => '#alerts',
'username' => 'AppLogger',
'icon_emoji' => ':warning:'
]
] );
$slackLogger = newLogger( $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

useNeuron\Log\Logger;
useNeuron\Log\Destination\Nightwatch;
useNeuron\Log\Format\NightwatchasNightwatchFormat;
// Create Nightwatch destination with default channel$nightwatch = newNightwatch( newNightwatchFormat() );
$nightwatch->open( [
'token' => $_ENV['NIGHTWATCH_TOKEN'], // Your Nightwatch API token'endpoint' => 'https://nightwatch.laravel.com/api/logs', // Optional, uses default'batch_size' => 10, // Optional: batch logs for better performance'timeout' => 5// Optional: API request timeout in seconds
] );
$nightwatchLogger = newLogger( $nightwatch );
$nightwatchLogger->setRunLevel( 'info' );
// Log messages will be sent to Nightwatch$nightwatchLogger->info( 'Application started' );
$nightwatchLogger->error( 'Database connection failed', [
'host' => 'db.example.com',
'port' => 3306,
'error' => 'Connection timeout'
] );
// For production use with the singletonuseNeuron\Log\Log;
// Add Nightwatch to the global logger
Log::getInstance()->Logger->addLog( $nightwatchLogger );
// Now all logs at info level and above go to Nightwatch
Log::info( 'User logged in', [ 'user_id' => 123 ] );
Log::warning( 'API rate limit approaching', [ 'requests' => 950, 'limit' => 1000 ] );
Log::error( 'Payment processing failed', [ 'transaction_id' => 'txn_abc123' ] );

Nightwatch with Channels

The channel name is automatically passed to Nightwatch when using named channels:

useNeuron\Log\Log;
useNeuron\Log\Logger;
useNeuron\Log\Destination\Nightwatch;
useNeuron\Log\Format\NightwatchasNightwatchFormat;
// Create a single Nightwatch format instance$nightwatchFormat = newNightwatchFormat( 'neuron', 'my-app' );
// Create Nightwatch destination$nightwatch = newNightwatch( $nightwatchFormat );
$nightwatch->open( [ 'token' => $_ENV['NIGHTWATCH_TOKEN'] ] );
// Create logger and add to multiple channels$logger = newLogger( $nightwatch );
Log::addChannel( 'audit', $logger );
Log::addChannel( 'security', $logger );
Log::addChannel( 'payments', $logger );
// Logs automatically include the channel name
Log::channel( 'audit' )->info( 'User updated profile', [ 'user_id' => 123 ] );
// Nightwatch receives: {"channel": "audit", "message": "User updated profile", ...}
Log::channel( 'security' )->warning( 'Failed login attempt', [ 'ip' => '192.168.1.1' ] );
// Nightwatch receives: {"channel": "security", "message": "Failed login attempt", ...}
Log::channel( 'payments' )->error( 'Payment failed', [ 'amount' => 99.99 ] );
// Nightwatch receives: {"channel": "payments", "message": "Payment failed", ...}

The channel name appears in the Nightwatch dashboard for easy filtering and monitoring.

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.

useNeuron\Log\Logger;
useNeuron\Log\Destination\Papertrail;
useNeuron\Log\Format\PlainText;
// Create Papertrail destination$papertrail = newPapertrail( newPlainText() );
$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 = newLogger( $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:

useNeuron\Log\Logger;
useNeuron\Log\Destination\Sqs;
useNeuron\Log\Format\JSON;
// Create SQS destination$sqs = newSqs( newJSON() );
$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 = newLogger( $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:

useNeuron\Log\Logger;
useNeuron\Log\Destination\WebSocket;
useNeuron\Log\Format\JSON;
// Create WebSocket destination$websocket = newWebSocket( newJSON() );
$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 = newLogger( $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)

useNeuron\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 formattingtry
{
// 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

useNeuron\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
```phpuse 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 channelsLog::addChannel( 'audit', $auditLogger );Log::addChannel( 'alerts', $alertLogger );// Use specific channelsLog::channel( 'audit' )->info( 'User login', [ 'user' => $username ] );Log::channel( 'alerts' )->emergency( 'System down!' );

Multiplexer (Multiple Destinations)

useNeuron\Log\LogMux;
useNeuron\Log\Logger;
useNeuron\Log\Destination\File;
useNeuron\Log\Destination\StdErr;
useNeuron\Log\Format\PlainText;
useNeuron\Log\Format\JSON;
// Create multiple loggers$fileLogger = newLogger( newFile( newJSON() ) );
$fileLogger->getDestination()->open( [ 'path' => '/var/log/app.json' ] );
$fileLogger->setRunLevel( 'debug' );
$consoleLogger = newLogger( newStdErr( newPlainText() ) );
$consoleLogger->setRunLevel( 'warning' );
// Create multiplexer$mux = newLogMux();
$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

useNeuron\Log\Logger;
useNeuron\Log\Adapter\Psr3Adapter;
useNeuron\Log\Destination\File;
useNeuron\Log\Format\JSON;
// Create a Neuron logger$destination = newFile( newJSON() );
$destination->open( [ 'path' => '/var/log/app.json' ] );
$neuronLogger = newLogger( $destination );
$neuronLogger->setRunLevel( 'info' );
// Wrap it with the PSR-3 adapter$psr3Logger = newPsr3Adapter( $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:

useNeuron\Log\Log;
useNeuron\Log\Adapter\Psr3Adapter;
// Get Neuron's singleton logger and wrap it$psr3Logger = newPsr3Adapter( 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 = newThirdPartyService( $psr3Logger );

Level Mapping

The adapter automatically maps PSR-3 log levels to Neuron's RunLevel enum:

PSR-3 LevelNeuron RunLevelNumeric Value
emergencyEMERGENCY50
alertALERT45
criticalCRITICAL40
errorERROR30
warningWARNING20
noticeNOTICE15
infoINFO10
debugDEBUG0

Advanced Features

The adapter maintains full compatibility with Neuron's advanced features:

useNeuron\Log\Logger;
useNeuron\Log\Adapter\Psr3Adapter;
useNeuron\Log\Destination\File;
useNeuron\Log\Format\JSON;
// Create Neuron logger with multiple destinations$fileLogger = newLogger( newFile( newJSON() ) );
$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 = newPsr3Adapter( $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?

  1. Framework Integration: Use Neuron's powerful logging with any PSR-3 expecting library
  2. Gradual Migration: Migrate from other PSR-3 loggers without changing application code
  3. Best of Both Worlds: Keep Neuron's advanced features (multiple destinations, formats, filters) while maintaining PSR-3 compatibility
  4. Drop-in Replacement: Works as a drop-in replacement for Monolog, PSR-3 Log, or other PSR-3 implementations

Custom Filters

useNeuron\Log\Logger;
useNeuron\Log\Filter\IFilter;
useNeuron\Log\RunLevel;
class ProductionFilter implements IFilter
{
publicfunctionshouldLog( RunLevel$level, string$message, array$context ): bool
{
// Don't log debug messages in productionif( $level === RunLevel::DEBUG && $_ENV['APP_ENV'] === 'production' )
{
returnfalse;
}
// Don't log sensitive dataif( str_contains( $message, 'password' ) || str_contains( $message, 'token' ) )
{
returnfalse;
}
returntrue;
}
}
$logger = newLogger( $destination );
$logger->addFilter( newProductionFilter() );

Advanced Configuration

Environment-Based Configuration

useNeuron\Log\Log;
useNeuron\Log\Logger;
useNeuron\Log\Destination\File;
useNeuron\Log\Destination\StdOut;
useNeuron\Log\Format\JSON;
useNeuron\Log\Format\PlainText;
$environment = $_ENV['APP_ENV'] ?? 'development';
if( $environment === 'production' )
{
// Production: JSON to file$destination = newFile( newJSON() );
$destination->open( [ 'path' => '/var/log/app.json' ] );
$runLevel = 'warning';
}
else
{
// Development: Plain text to console$destination = newStdOut( newPlainText( true ) );
$runLevel = 'debug';
}
$logger = newLogger( $destination );
$logger->setRunLevel( $runLevel );
Log::getInstance()->Logger->addLog( $logger );

Testing with Memory Logger

useNeuron\Log\Logger;
useNeuron\Log\Destination\Memory;
useNeuron\Log\Format\Raw;
// For unit testing$memoryDestination = newMemory( newRaw() );
$testLogger = newLogger( $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 troubleshooting
  • info (10) - Informational messages about application flow
  • notice (15) - Normal but significant events
  • warning (20) - Warning messages about potentially harmful situations
  • error (30) - Error events that allow the application to continue running
  • critical (40) - Critical conditions that need immediate attention
  • alert (45) - Action must be taken immediately
  • emergency (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

About

Comprehensive logging package. Supports multiple destinations and formats including stdout, stderr, files, slack, sockets and webhooks.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages