adminintelligence/laravel-log-shipper

Ships your Laravel logs to a central server. Because local problems deserve global visibility.

Installs: 66

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/adminintelligence/laravel-log-shipper

v1.1.0 2025-12-11 16:58 UTC

This package is auto-updated.

Last update: 2025-12-15 15:21:14 UTC


README

Tests Latest Version on Packagist License

A Laravel package that ships your application logs to a central server.

Companion Service: Logger

This package is designed to work with Logger — a centralized log aggregation service built with Laravel.

Logger provides:

  • Web Dashboard — Search, filter, and browse logs with pagination
  • Multi-Project Support — Manage logs from multiple applications with isolated project keys
  • Failing Controllers Report — Identify error hotspots by controller
  • Retention Policies — Configurable per-project log retention (7, 14, 30, 90 days, or infinite)
  • Webhook Notifications — Slack/Discord/Mattermost-compatible alerts for errors and critical events
  • Dark Mode — Full dark theme support

Note: You can also use this package with any HTTP endpoint that accepts JSON log payloads.

Requirements

  • PHP 8.1 or higher
  • Laravel 10, 11, or 12
  • A queue driver (recommended: Redis, database, or SQS)

Installation

composer require adminintelligence/laravel-log-shipper

Configuration

Publish the configuration file:

php artisan vendor:publish --tag=log-shipper-config

Add the following to your .env file:

LOG_SHIPPER_ENABLED=true
LOG_SHIPPER_ENDPOINT=https://your-log-server.com/api/ingest
LOG_SHIPPER_KEY=your-project-api-key
LOG_SHIPPER_QUEUE=redis
LOG_SHIPPER_QUEUE_NAME=logs

Upgrading Configuration

If you're upgrading from a previous version and want to use the new features (IP obfuscation, enhanced status metrics, etc.), republish the configuration file:

php artisan vendor:publish --tag=log-shipper-config --force

⚠️ Warning: This will overwrite your existing config/log-shipper.php file. Make sure to back up any custom configurations first, or manually merge the new options from the published config.

New configuration options in recent versions:

  • ip_obfuscation - Privacy-compliant IP address obfuscation
  • max_payload_size - Payload size limiting for security
  • status.metrics.foldersize - Folder size monitoring
  • status.metrics.node_npm - Node.js and npm version detection
  • status.metrics.dependency_checks - Outdated package detection
  • status.metrics.security_audits - Security vulnerability scanning
  • status.monitored_folders - Folders to monitor for size metrics

Usage

Add the log shipper channel to your config/logging.php:

'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['daily', 'log_shipper'],
        'ignore_exceptions' => false,
    ],

    'log_shipper' => [
        'driver' => 'custom',
        'via' => \AdminIntelligence\LogShipper\Logging\CreateCustomLogger::class,
        'level' => 'error', // Only ship errors and above
    ],
    
    // ... other channels
],

Now any log at the configured level or above will be shipped to your central server:

Log::error('Something went wrong', ['order_id' => 123]);

Configuration Options

Option Description Default
enabled Enable/disable log shipping true
api_endpoint The URL of your log server -
api_key Your project's API key -
queue_connection Queue connection to use default
queue_name Queue name for log jobs default
retries Number of attempts before failing 3
backoff Wait time between retries (seconds) [2, 5, 10]
circuit_breaker Circuit breaker configuration enabled
fallback_channel Local channel to use if shipping fails null
sanitize_fields Fields to redact from logs See config
send_context Context data to include See config

Log Payload

When a log event is shipped, the following data is sent:

Core Log Data (Always Sent)

Field Type Description
level string Log level (error, warning, info, debug, etc.)
message string The log message
context array Any context array passed to the log call
datetime string Timestamp in Y-m-d H:i:s.u format
channel string The logging channel name
extra array Additional Monolog processor data

Optional Context Data

These fields can be toggled via the send_context configuration:

Field Type Default Description
user_id int|null enabled Authenticated user's ID
ip_address string|null enabled Client IP address
user_agent string|null enabled Browser/client user agent string
request_method string|null enabled HTTP method (GET, POST, PUT, DELETE, etc.)
request_url string|null enabled Full request URL including query string
route_name string|null enabled Laravel route name
controller_action string|null enabled Controller and action handling the request
app_env string|null enabled Application environment (local, staging, production)
app_debug bool|null enabled Whether debug mode is enabled
referrer string|null enabled HTTP Referer header

To disable specific context fields, update your config/log-shipper.php:

'send_context' => [
    'user_id' => true,
    'ip_address' => true,
    'user_agent' => false, // disabled
    // ...
],

Example Log Payload

Here is an example of the JSON payload sent for a log event:

{
    "level": "error",
    "message": "Order processing failed",
    "context": {
        "order_id": 12345,
        "reason": "Payment declined"
    },
    "datetime": "2025-12-11 14:30:45.123456",
    "channel": "local",
    "extra": {},
    "user_id": "1",
    "ip_address": "127.0.0.1",
    "user_agent": "Mozilla/5.0...",
    "request_method": "POST",
    "request_url": "https://api.example.com/orders",
    "route_name": "orders.store",
    "controller_action": "App\\Http\\Controllers\\OrderController@store",
    "app_env": "production",
    "app_debug": false
}

Status Monitoring

The package can automatically push system health metrics to your log server on a configurable interval. This helps you monitor the health of your application instances.

Enable Status Push

Add the following to your .env file:

LOG_SHIPPER_STATUS_ENABLED=true
LOG_SHIPPER_STATUS_ENDPOINT=https://your-log-server.com/api/stats
LOG_SHIPPER_STATUS_INTERVAL=5 # minutes (default: 5)

You can also configure the disk path to monitor:

LOG_SHIPPER_DISK_PATH=/

Interval Configuration

The LOG_SHIPPER_STATUS_INTERVAL setting supports flexible scheduling:

Interval Behavior Example
1-59 Every N minutes 5 = Every 5 minutes
60-1439 Every N hours 120 = Every 2 hours, 180 = Every 3 hours
1440+ Daily 1440 = Daily at midnight

The scheduler automatically selects the appropriate cron expression based on your interval value.

Collected Metrics

Note: Status pushing relies on Laravel's scheduler. Ensure you have the scheduler running: * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

Example Status Payload

Here is an example of the JSON payload sent for a status update:

{
    "timestamp": "2025-12-11T14:30:45+00:00",
    "app_name": "Laravel",
    "app_env": "production",
    "app_debug": false,
    "instance_id": "web-server-01",
    "log_shipper_version": "1.0.0",
    "system": {
        "memory_usage": 25165824,
        "memory_peak": 26214400,
        "server_memory": {
            "total": 17179869184,
            "free": 4294967296,
            "used": 12884901888,
            "percent_used": 75.0
        },
        "cpu_usage": 12.5,
        "php_version": "8.3.0",
        "laravel_version": "11.0.0",
        "uptime": 86400,
        "disk_space": {
            "total": 100000000000,
            "free": 60000000000,
            "used": 40000000000,
            "percent_used": 40.0
        }
    },
    "queue": {
        "size": 15,
        "connection": "redis",
        "queue": "default"
    },
    "database": {
        "status": "connected",
        "latency_ms": 1.2
    },
    "filesize": {
        "laravel.log": 102400
    },
    "foldersize": {
        "logs": 5242880
    }
}

System Metrics Details

The status payload includes the following system metrics:

System Object

Field Type Description
memory_usage int Current memory usage of the PHP process (bytes)
memory_peak int Peak memory usage of the PHP process (bytes)
server_memory object Server-level RAM metrics (see below)
cpu_usage float|null CPU usage percentage or load average
php_version string PHP version
laravel_version string Laravel framework version
uptime int|null System uptime in seconds (null if unavailable)
disk_space object Disk space metrics for monitored path
node_version string|null Node.js version (if enabled)
npm_version string|null npm version (if enabled)
composer_outdated int Count of outdated Composer packages (if enabled)
npm_outdated int Count of outdated npm packages (if enabled)
composer_audit int Count of Composer security advisories (if enabled)
npm_audit int Count of npm security vulnerabilities (if enabled)

Server Memory Object

Field Type Description
total int|null Total system RAM (bytes)
free int|null Available system RAM (bytes)
used int|null Used system RAM (bytes)
percent_used float|null Percentage of RAM in use

Note on macOS: The percent_used includes filesystem cache. This is normal macOS behavior and does not indicate memory pressure.

Queue Object

  • Size: Queue jobs count (excluding the status job itself)
  • Connection: Active queue connection

Database Object

  • Status: Connection status (connected or disconnected)
  • Latency: Query latency in milliseconds

Cache Object

  • Driver: Active cache driver

Filesize Object

  • Files: Sizes of specific monitored files (configurable)

Foldersize Object

  • Folders: Total sizes of specific monitored folders, including all nested files (configurable)

To configure which metrics are sent or to monitor specific files/folders, publish the config and update the status section:

'status' => [
    'metrics' => [
        'system' => true,
        'queue' => true,
        'database' => true,
        'cache' => false,
        'filesize' => true,
        'foldersize' => true,
        
        // Optional expensive metrics (disabled by default)
        'node_npm' => false,              // Node.js and npm versions
        'dependency_checks' => false,     // Outdated package counts
        'security_audits' => false,       // Security vulnerability counts
    ],

    'monitored_files' => [
        storage_path('logs/laravel.log'),
        storage_path('logs/worker.log'),
    ],
    
    'monitored_folders' => [
        storage_path('logs'),
        storage_path('app/cache'),
    ],
],

Performance Note: The optional metrics (node_npm, dependency_checks, security_audits) can be slow as they execute shell commands. Enable these only if you need them and have increased the job timeout accordingly (default: 120 seconds).

Note: Status pushing relies on Laravel's scheduler. Ensure you have the scheduler running: * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

Data Sanitization

The package automatically redacts sensitive fields from your logs. The following field patterns are redacted by default:

Field Pattern Examples
password password, user_password, password_hash
password_confirmation password_confirmation
credit_card credit_card, credit_card_number
card_number card_number
cvv cvv, card_cvv
api_key api_key, stripe_api_key
secret secret, client_secret
token token, access_token, refresh_token
authorization authorization

Add additional fields to sanitize in the config file:

'sanitize_fields' => [
    'password',
    'credit_card',
    'ssn', // add your own
    // ...
],

IP Address Obfuscation

For privacy compliance (GDPR, CCPA), you can enable IP address obfuscation to anonymize client IP addresses before they are logged.

Enable IP Obfuscation

Add the following to your .env file:

LOG_SHIPPER_IP_OBFUSCATION_ENABLED=true
LOG_SHIPPER_IP_OBFUSCATION_METHOD=mask # or 'hash'

Obfuscation Methods

Mask (Default)

Zeroes out the last octet of IPv4 addresses and the last 64 bits of IPv6 addresses:

  • IPv4: 192.168.1.100192.168.1.0
  • IPv6: 2001:db8:85a3::8a2e:370:73342001:db8:85a3::

This method preserves geographic information while protecting individual privacy.

Hash

Generates a one-way hash of the IP address:

  • IPv4: 192.168.1.100ip_a3f5c8e91d2b4f67
  • IPv6: 2001:db8:85a3::8a2e:370:7334ip_b9e4d1c72a8f3e56

This method provides maximum privacy while maintaining consistency (the same IP always produces the same hash).

Configuration

// config/log-shipper.php
'ip_obfuscation' => [
    'enabled' => env('LOG_SHIPPER_IP_OBFUSCATION_ENABLED', false),
    'method' => env('LOG_SHIPPER_IP_OBFUSCATION_METHOD', 'mask'), // 'mask' or 'hash'
],

Security Features

HTTPS Enforcement

In production environments, the package automatically enforces HTTPS for the API endpoint. HTTP endpoints will be rejected to prevent credential leaks.

# Accepted in production
LOG_SHIPPER_ENDPOINT=https://secure.example.com/api/ingest

# Rejected in production (only allowed in local/staging/testing)
LOG_SHIPPER_ENDPOINT=http://insecure.example.com/api/ingest

Payload Size Limits

To prevent denial-of-service attacks via oversized log payloads, the package limits the maximum payload size:

// config/log-shipper.php
'max_payload_size' => env('LOG_SHIPPER_MAX_PAYLOAD_SIZE', 1048576), // 1MB default

If a payload exceeds this limit, the context will be truncated and marked with _truncated: true.

Sync Mode

By default, logs are shipped via queued jobs for better performance. If you prefer synchronous shipping (useful for debugging or simple setups), set:

LOG_SHIPPER_QUEUE=sync

Note: Sync mode will block your application until the HTTP request completes. Use queued mode in production for better performance.

Batch Shipping

For high-traffic applications, dispatching a job for every log event can create significant queue pressure. You can enable batch shipping to buffer logs in Redis and ship them in chunks.

Enable Batch Shipping

Add the following to your .env file:

LOG_SHIPPER_BATCH_ENABLED=true
LOG_SHIPPER_BATCH_SIZE=100
LOG_SHIPPER_BATCH_INTERVAL=1 # Run every minute

Requirements

  • Redis connection (configured in config/database.php)
  • Laravel Scheduler running

How it Works

  1. Logs are pushed to a Redis list (log_shipper_buffer) instead of dispatching a job immediately.
  2. A scheduled command (log-shipper:ship-batch) runs every minute.
  3. The command pops logs in batches (default: 100) and dispatches a single job per batch.
  4. The job ships the batch to the log server in a single HTTP request.

Reliability & Fault Tolerance

This package includes built-in mechanisms to ensure your application remains stable even if the log server is down.

Retries & Backoff

If the log server returns a 4xx/5xx error or is unreachable, the job will automatically retry based on your configuration.

// config/log-shipper.php
'retries' => 3,
'backoff' => [2, 5, 10], // Wait 2s, then 5s, then 10s

Circuit Breaker

To prevent your queue from being flooded with failing jobs during an outage, the Circuit Breaker will temporarily stop dispatching new log jobs.

// config/log-shipper.php
'circuit_breaker' => [
    'enabled' => true,
    'failure_threshold' => 5, // Open circuit after 5 consecutive failures
    'duration' => 300, // Keep circuit open for 5 minutes
],

When the circuit is open, logs are skipped entirely to protect your application's performance.

Fallback Channel

If the log shipper fails to send logs (after all retries are exhausted), you can configure a fallback channel to ensure logs are not lost.

Add the following to your .env file:

LOG_SHIPPER_FALLBACK=daily

When a failure occurs, the original log payload will be written to the specified channel, along with failure details in the context.

Important: Do not set the fallback channel to log_shipper itself, as this will create an infinite loop. The package automatically prevents this scenario.

Changelog

Please see CHANGELOG.md for more information on what has changed recently.

Contributing

Please see CONTRIBUTING.md for details.

Security

If you discover a security vulnerability, please see SECURITY.md for reporting instructions.

License

The MIT License (MIT). Please see LICENSE for more information.