PHPackages                             antlerops/error-logger - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. antlerops/error-logger

ActiveLibrary

antlerops/error-logger
======================

Advanced error logger with multiple transport options and rate limiting

v3.0.0(12mo ago)020MITPHPPHP ^7.1 || ^8.0

Since May 2Pushed 11mo ago1 watchersCompare

[ Source](https://github.com/antlerops/error-logger)[ Packagist](https://packagist.org/packages/antlerops/error-logger)[ RSS](/packages/antlerops-error-logger/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)DependenciesVersions (15)Used By (0)

Antler Error Logger
===================

[](#antler-error-logger)

An advanced PHP error logging system with comprehensive context capture, multiple transport options, and robust error handling for PHP 7.1+ and PHP 8.0+ applications.

Features
--------

[](#features)

- **Multi-Transport Logging**: Log to remote endpoints, local files, and PHP error log simultaneously
- **Enhanced Stack Traces**: Captures source code context around errors with line numbers
- **Intelligent Environment Detection**: Automatically captures different context in CLI vs. web environments
- **Rich Context**: Captures system state, execution performance, HTTP request details, and more
- **Privacy-Aware**: Automatically sanitizes sensitive data (passwords, tokens, etc.)
- **Rate Limiting**: Prevents log flooding during high-volume error situations
- **Performance Monitoring**: Tracks memory usage and execution time for errors
- **Simple Integration**: Drop-in error handling with minimal configuration
- **Container-Aware**: Detects containerized environments
- **Contextual Tagging**: Tag logs for better categorization and filtering
- **Request Tracking**: Correlate logs from the same request with request IDs
- **Performance Instrumentation**: Built-in timers for measuring code execution time
- **Nested Context**: Maintain hierarchical context through code execution
- **Sampling**: Control log volume with configurable sampling rates
- **Circuit Breaker**: Prevent log flooding during error cascades
- **Log Filtering**: Filter logs based on message patterns or context values
- **Asynchronous Processing**: Non-blocking log processing for better performance

Installation
------------

[](#installation)

```
composer require antlerops/error-logger
```

Basic Usage
-----------

[](#basic-usage)

```
use Antler\ErrorLogger\Logger;
use Antler\ErrorLogger\LoggerConfig;
use Antler\ErrorLogger\LogLevel;

// Quick setup with minimal configuration
$config = new LoggerConfig([
    'project_hash' => 'your-project-identifier',
    'remote_endpoint' => 'LOCAL_DOMAIN/api/log/rec'
]);

$logger = Logger::getInstance($config);

// Log examples
$logger->debug('SQL query executed', ['query' => $sql, 'duration' => $queryTime]);
$logger->info('User logged in', ['user_id' => $userId]);
$logger->warning('Deprecated feature used', ['feature' => 'oldApi']);
$logger->error('Payment failed', ['order_id' => $orderId, 'amount' => $amount]);
$logger->critical('System is out of disk space');

// Exceptions are automatically captured by the global handler
// but you can also log caught exceptions with full context
try {
    // Your code
} catch (Exception $e) {
    $logger->error('Caught exception', [
        'exception' => get_class($e),
        'message' => $e->getMessage(),
        'code' => $e->getCode()
    ]);
}
```

Configuration Options
---------------------

[](#configuration-options)

Config KeyDefault ValueDescription`project_hash``null`**Required**: Unique project identifier`remote_endpoint``null`Remote logging API URL (Required for remote logging)`log_file_path``./logs/application.log`Path to local log file`request_timeout``2`Timeout in seconds for remote requests`min_log_level``LogLevel::WARNING`Minimum severity level to log (DEBUG to CRITICAL)`use_remote_logging``true`Enable/disable remote logging`use_file_logging``true`Enable/disable local file logging`use_error_log``true`Use PHP error\_log() for ERROR+ levels`rate_limit_per_minute``60`Maximum allowed logs per minute to prevent flooding`sampling_rate``1.0`Sampling rate for logs (0.0 to 1.0)`circuit_breaker_threshold``0`Errors per minute to trigger circuit breaker (0=disabled)`circuit_breaker_cooldown``60`Seconds to keep circuit breaker open`async_processing``false`Send logs asynchronously (non-blocking)Environment Variables
---------------------

[](#environment-variables)

All configuration options can be set via environment variables:

```
ANTLER_PROJECT_HASH="your-project-hash"
ANTLER_LOG_ENDPOINT="LOCAL_DOMAIN/api/log/rec"
ANTLER_LOG_FILE_PATH="/var/log/app.log"
ANTLER_LOG_REQUEST_TIMEOUT="3"
ANTLER_LOG_MIN_LOG_LEVEL="DEBUG"  # DEBUG, INFO, WARNING, ERROR, CRITICAL
ANTLER_LOG_USE_REMOTE_LOGGING="true"
ANTLER_LOG_USE_FILE_LOGGING="true"
ANTLER_LOG_USE_ERROR_LOG="true"
ANTLER_LOG_RATE_LIMIT_PER_MINUTE="100"
ANTLER_LOG_SAMPLING_RATE="1.0"
ANTLER_LOG_CIRCUIT_BREAKER_THRESHOLD="0"
ANTLER_LOG_CIRCUIT_BREAKER_COOLDOWN="60"
ANTLER_LOG_ASYNC_PROCESSING="false"
```

Configuration in code overrides environment variables.

Enhanced Stack Traces with Code Context
---------------------------------------

[](#enhanced-stack-traces-with-code-context)

One of the powerful features of Antler Error Logger is the ability to capture detailed code context around errors. This makes debugging easier by showing you exactly what was happening in your code when the error occurred:

```
try {
    throw new Exception("Something went wrong");
} catch (Exception $e) {
    $logger->error("Caught exception", ["exception" => $e]);
}
```

This will include the enhanced stack trace with source code context in your logs.

Log Levels
----------

[](#log-levels)

The logger offers five standard severity levels:

```
LogLevel::DEBUG    // 100 - Detailed information for debugging
LogLevel::INFO     // 200 - Interesting events in your application
LogLevel::WARNING  // 300 - Non-error but potentially problematic situations
LogLevel::ERROR    // 400 - Runtime errors that don't require immediate action
LogLevel::CRITICAL // 500 - Critical errors requiring immediate intervention
```

Contextual Tagging
------------------

[](#contextual-tagging)

Tags allow you to categorize log entries for easier filtering and analysis.

```
// Set default tags for all logs
$logger->setDefaultTags(['app:api', 'env:production']);

// Log with specific tags
$logger->error("Payment failed", [
    'order_id' => 12345,
    'tags' => ['module:payments', 'customer:premium']
]);

// Result will include tags: ['app:api', 'env:production', 'module:payments', 'customer:premium']
```

Log Entry and Request Tracking
------------------------------

[](#log-entry-and-request-tracking)

Each log entry now includes a unique ID, and logs from the same request are linked with a request ID:

```
// All logs created in the same request will share the same request_id
$logger->info("Processing started");
$logger->debug("Query executed", ['query' => $sql]);
$logger->info("Processing completed");

// For web requests, any existing X-Request-ID header will be used as the request ID
```

Performance Instrumentation
---------------------------

[](#performance-instrumentation)

Track execution time and memory usage:

```
// Start a timer
$logger->startTimer('database_query');

// Run database query
$results = $db->query($sql);

// Stop timer and log results
$logger->stopTimer('database_query', 'User search query completed', [
    'query' => $sql,
    'result_count' => count($results)
]);

// Log output will include duration_ms and memory_usage
```

Nested Context Support
----------------------

[](#nested-context-support)

Maintain a context stack throughout code execution:

```
// Push user context
$logger->pushContext(['user_id' => 123, 'role' => 'admin']);

// Log something with this context automatically included
$logger->info('User accessed admin panel');

// Push another context for a specific operation
$logger->pushContext(['operation' => 'user_update']);

// This log will have both user and operation context
$logger->info('Changed user email', ['old_email' => 'old@example.com', 'new_email' => 'new@example.com']);

// Pop operation context when done
$logger->popContext();

// This log will only have the user context
$logger->info('Admin panel exited');

// Pop user context
$logger->popContext();
```

Sampling and Circuit Breaker
----------------------------

[](#sampling-and-circuit-breaker)

Reduce log volume in high-traffic scenarios:

```
// Configure log sampling (log 10% of entries)
$config = new LoggerConfig([
    'project_hash' => 'your-project',
    'sampling_rate' => 0.1, // Log 10% of entries
]);

// Configure circuit breaker (stop logging errors after threshold reached)
$config = new LoggerConfig([
    'project_hash' => 'your-project',
    'circuit_breaker_threshold' => 100, // Open circuit after 100 errors per minute
    'circuit_breaker_cooldown' => 60,   // Keep circuit open for 60 seconds
]);

$logger = Logger::getInstance($config);
```

Log Filtering
-------------

[](#log-filtering)

Filter out unwanted log entries:

```
$config = new LoggerConfig([
    'project_hash' => 'your-project'
]);

// Add a message pattern filter (regex)
$config->addMessageFilter('/^Cache miss for key/');

// Add a context key/value filter (exact match)
$config->addContextFilter('status_code', 404);

// Add a context regex filter
$config->addContextFilter('url', '/\.jpg$/', true);

$logger = Logger::getInstance($config);
```

Asynchronous Processing
-----------------------

[](#asynchronous-processing)

Process logs without blocking application execution:

```
$config = new LoggerConfig([
    'project_hash' => 'your-project',
    'remote_endpoint' => 'https://your-log-endpoint.com',
    'async_processing' => true
]);

$logger = Logger::getInstance($config);

// Logs will be sent asynchronously without blocking
$logger->info("User registered", ['user_id' => $userId]);
```

Automatic Context Capture
-------------------------

[](#automatic-context-capture)

The logger automatically captures different information depending on the execution environment:

### Common to Both CLI and Web

[](#common-to-both-cli-and-web)

- Project identifier
- PHP version and SAPI
- Memory usage, peak, and growth since logger initialization
- Memory limit
- Execution time
- Maximum execution time
- Operating system
- Timezone
- Server hostname
- Process ID
- Container detection

### CLI-Specific Context

[](#cli-specific-context)

- Script arguments (argc/argv)
- Script filename
- Current working directory
- Current user

### Web-Specific Context

[](#web-specific-context)

- Full URL and components (scheme, host, path)
- HTTP method
- Query parameters (sanitized)
- Client IP address
- User agent
- Referrer
- HTTP headers
- Request body (JSON or form data, sanitized)
- Session information (when available)

Data Privacy and Sanitization
-----------------------------

[](#data-privacy-and-sanitization)

The logger automatically redacts sensitive information from request data. Fields containing the following strings will be redacted:

- password, passwd
- secret, token, auth
- key, apikey, api\_key
- access\_token, accesstoken
- credential, private
- ssn, social\_security
- cc, card, credit, cvv, cvc

For example:

```
{
    "user": "johndoe",
    "api_key": "[REDACTED]",
    "password": "[REDACTED]",
    "metadata": {
        "access_token": "[REDACTED]"
    }
}
```

Remote Payload Example
----------------------

[](#remote-payload-example)

Here's an example of what the logger sends to remote endpoints, including the enhanced stack trace:

```
{
  "project_hash": "example-project",
  "uuid": "log_5e9f8a7b6c5d4",
  "request_id": "d4c3b2a1-e5f6-7g8h",
  "timestamp": "2023-09-15T14:23:01+00:00",
  "level": 400,
  "level_name": "ERROR",
  "message": "Database connection failed",
  "tags": ["app:api", "env:production"],
  "context": {
    "exception_class": "PDOException",
    "file": "/var/www/app/src/Database.php",
    "line": 45,
    "code": 1045,
    "enhanced_trace": {
      "frames": [
        {
          "file": "/var/www/app/src/Database.php",
          "line": 45,
          "function": null,
          "class": null,
          "type": null,
          "args": [],
          "code_context": {
            "file": "/var/www/app/src/Database.php",
            "line": 45,
            "start_line": 40,
            "end_line": 50,
            "context": {
              "40": {
                "content": "    public function connect() {",
                "is_error_line": false
              },
              "41": {
                "content": "        try {",
                "is_error_line": false
              },
              "42": {
                "content": "            $dsn = sprintf(",
                "is_error_line": false
              },
              "43": {
                "content": "                'mysql:host=%s;dbname=%s;charset=utf8mb4',",
                "is_error_line": false
              },
              "44": {
                "content": "                $this->config['host'], $this->config['database']",
                "is_error_line": false
              },
              "45": {
                "content": "            $this->pdo = new PDO($dsn, $this->config['user'], $this->config['password']);",
                "is_error_line": true
              },
              "46": {
                "content": "            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);",
                "is_error_line": false
              },
              "47": {
                "content": "            return true;",
                "is_error_line": false
              },
              "48": {
                "content": "        } catch (PDOException $e) {",
                "is_error_line": false
              },
              "49": {
                "content": "            throw $e;",
                "is_error_line": false
              },
              "50": {
                "content": "        }",
                "is_error_line": false
              }
            }
          }
        },
        {
          "file": "/var/www/app/src/App.php",
          "line": 28,
          "function": "connect",
          "class": "Database",
          "type": "->",
          "args": [],
          "code_context": {
            "file": "/var/www/app/src/App.php",
            "line": 28,
            "start_line": 23,
            "end_line": 33,
            "context": {
              "23": {
                "content": "    public function initialize() {",
                "is_error_line": false
              },
              "24": {
                "content": "        // Load configuration",
                "is_error_line": false
              },
              "25": {
                "content": "        $this->config = require __DIR__ . '/../config/config.php';",
                "is_error_line": false
              },
              "26": {
                "content": "",
                "is_error_line": false
              },
              "27": {
                "content": "        // Initialize database",
                "is_error_line": false
              },
              "28": {
                "content": "        $this->db->connect();",
                "is_error_line": true
              },
              "29": {
                "content": "",
                "is_error_line": false
              },
              "30": {
                "content": "        // Set up routes",
                "is_error_line": false
              },
              "31": {
                "content": "        $this->setupRoutes();",
                "is_error_line": false
              },
              "32": {
                "content": "    }",
                "is_error_line": false
              },
              "33": {
                "content": "",
                "is_error_line": false
              }
            }
          }
        }
      ],
      "exception_class": "PDOException",
      "message": "SQLSTATE[HY000] [1045] Access denied for user 'webapp'@'172.18.0.3' (using password: YES)",
      "code": 1045
    },
    "trace": "PDOException: SQLSTATE[HY000] [1045]... (truncated for brevity)"
  },
  "system": {
    "php_version": "8.1.12",
    "os": "Linux",
    "memory_usage": "14.2 MB",
    "memory_peak": "16.5 MB",
    "memory_growth": "7.5 MB",
    "memory_limit": "128M",
    "execution_time": "0.1234s",
    "max_execution_time": "30",
    "timezone": "UTC",
    "sapi": "fpm-fcgi",
    "server_software": "nginx/1.20.1"
  },
  "environment": {
    "environment": "production",
    "server_name": "web-prod-03",
    "process_id": 12345,
    "container": true
  },
  "web": {
    "method": "POST",
    "url": "https://api.example.com/users",
    "path": "/users",
    "query_string": "source=signup",
    "ip": "203.0.113.42",
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "referer": "https://example.com/signup",
    "protocol": "HTTP/1.1",
    "port": "443",
    "host": "api.example.com",
    "https": true,
    "query_params": {
      "source": "signup"
    }
  },
  "headers": {
    "Accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "[REDACTED]"
  },
  "request_body": {
    "name": "John Doe",
    "email": "john@example.com",
    "password": "[REDACTED]"
  },
  "session": {
    "id": "abc123def456",
    "data_size": "2.3 KB"
  }
}
```

Advanced Configuration Examples
-------------------------------

[](#advanced-configuration-examples)

### Development Environment

[](#development-environment)

```
// For local development, keep file logging but disable remote
$logger = Logger::getInstance(new LoggerConfig([
    'project_hash' => 'dev-project',
    'use_remote_logging' => false,
    'log_file_path' => __DIR__ . '/logs/dev.log',
    'min_log_level' => LogLevel::DEBUG
]));
```

### High-Traffic Production Environment

[](#high-traffic-production-environment)

```
// For high-traffic production, focus on performance
$logger = Logger::getInstance(new LoggerConfig([
    'project_hash' => 'prod-project',
    'remote_endpoint' => 'LOCAL_DOMAIN/api/log/rec',
    'min_log_level' => LogLevel::ERROR,
    'use_file_logging' => false,       // Skip file logging for performance
    'rate_limit_per_minute' => 200,    // Higher rate limit
    'request_timeout' => 1,            // Lower timeout to prevent blocking
    'sampling_rate' => 0.2,            // Sample 20% of all logs
    'async_processing' => true         // Async processing for better performance
]));
```

### CLI Application Example

[](#cli-application-example)

```
// For CLI applications, customize log path by command
$logger = Logger::getInstance(new LoggerConfig([
    'project_hash' => 'cli-app',
    'log_file_path' => __DIR__ . '/logs/' . basename($argv[0]) . '.log',
    'use_remote_logging' => true,
    'min_log_level' => LogLevel::INFO
]));
```

Laravel Integration
-------------------

[](#laravel-integration)

Antler Error Logger integrates easily with Laravel applications thanks to its singleton pattern. This section covers how to use the error logger directly in Laravel without additional facades or service providers.

### Supported Laravel Versions

[](#supported-laravel-versions)

Antler Error Logger is compatible with the following Laravel versions:

Laravel VersionPHP CompatibilitySupport StatusLaravel 6.xPHP 7.2 or higher✓ SupportedLaravel 7.xPHP 7.2.5 or higher✓ SupportedLaravel 8.xPHP 7.3 or higher✓ SupportedLaravel 9.xPHP 8.0.2 or higher✓ SupportedLaravel 10.xPHP 8.1 or higher✓ SupportedLaravel 11.xPHP 8.2 or higher✓ SupportedLaravel 12.xPHP 8.2 or higher✓ Supported> **Note**: For PHP 7.1 compatibility, you must use Laravel 5.8 or earlier. Laravel 6.0+ requires PHP 7.2+.

### Simple Installation

[](#simple-installation)

1. Install the package via Composer:

```
composer require antlerops/error-logger
```

2. That's it! No service providers or facades required.

### Basic Usage in Laravel

[](#basic-usage-in-laravel)

Since the Antler Error Logger uses a singleton pattern, you can access it directly in your Laravel application:

```
use Antler\ErrorLogger\Logger;
use Antler\ErrorLogger\LoggerConfig;
use Antler\ErrorLogger\LogLevel;

// In any controller, middleware, or service

// Initialize once with your configuration (in a bootstrap file or service provider)
$config = new LoggerConfig([
    'project_hash' => env('ANTLER_PROJECT_HASH', 'your-project-identifier'),
    'remote_endpoint' => env('ANTLER_LOG_ENDPOINT', 'https://your-log-endpoint.com'),
    'log_file_path' => storage_path('logs/antler.log'),
    'min_log_level' => LogLevel::WARNING,
]);

// Get the singleton instance
$logger = Logger::getInstance($config);

// Then use it anywhere in your application
Logger::getInstance()->info('User logged in', ['user_id' => auth()->id()]);
Logger::getInstance()->error('Payment failed', ['order_id' => $orderId]);
```

### Recommended Setup in Laravel

[](#recommended-setup-in-laravel)

#### Bootstrap Integration

[](#bootstrap-integration)

A clean way to integrate the logger is by initializing it in a service provider. You can use Laravel's `AppServiceProvider` or create a dedicated provider:

```
