Skip to content

05 Advanced Topics

github-actions[bot] edited this page Sep 27, 2025 · 1 revision

Advanced Topics

This section covers more complex usage patterns, customization, and best practices for production environments.

Multi-Channel, Multi-Handler Logging

A powerful feature of the library is the ability to route different logs to different handlers. You can combine multiple handlers, each configured for specific channels or severity levels, to create a sophisticated logging strategy.

Example Scenario

Imagine you have a plugin that processes payments and interacts with an external API. Your logging requirements are:

  • Log all events to a file for general debugging.
  • Log all payment and API events to the database for auditing.
  • Receive an email notification only for critical errors related to payments.
<?php
global $wpdb;
use Psr\Log\LogLevel;
use WPTechnix\WP_Simple_Logger\Manager;
use WPTechnix\WP_Simple_Logger\Handlers\File_Handler;
use WPTechnix\WP_Simple_Logger\Handlers\Database_Handler;
use WPTechnix\WP_Simple_Logger\Handlers\Email_Handler;

$manager = new Manager();

// Handler 1: Log everything to a file.
$file_handler = new File_Handler( WP_CONTENT_DIR . '/logs/full_app.log' );
$manager->add_handler( $file_handler ); // No channel or level restriction.

// Handler 2: Log 'payments' and 'api' channels to the database.
$db_handler = new Database_Handler( $wpdb->prefix . 'app_logs' );
$db_handler->set_channels( ['payments', 'api'] ); // Restrict to specific channels.
$manager->add_handler( $db_handler );

// Handler 3: Email only critical errors from the 'payments' channel.
$email_handler = new Email_Handler(
    '[email protected]', 
    'Critical Payment Error', 
    LogLevel::CRITICAL // Only handles CRITICAL level and higher.
);
$email_handler->set_channels( ['payments'] ); // Only handles the 'payments' channel.
$manager->add_handler($email_handler);

// Initialize the manager to register all hooks.
$manager->init();

// --- Usage Example ---
$payment_logger = $manager->get_logger('payments');
$api_logger = $manager->get_logger('api');
$general_logger = $manager->get_logger('general');

// This goes to File and Database.
$payment_logger->info('Payment initiated.', ['order_id' => 123]);

// This goes to File only.
$general_logger->debug('User session started.');

// This goes to File, Database, AND Email.
$payment_logger->critical('Payment gateway timeout!', ['gateway' => 'Stripe']);

Customization Guide

The library is designed to be extended. You can easily create your own handlers and formatters by implementing the provided interfaces.

Creating a Custom Handler

To create a custom handler (e.g., to send logs to Slack), you should extend Abstract_Handler to get level-checking, channel filtering, and formatter logic for free.

  1. Create a class that extends \WPTechnix\WP_Simple_Logger\Handlers\Abstract_Handler.
  2. Implement the handle(Log_Entry $entry) and flush() methods.

Example: A Simple Slack Handler

<?php
use WPTechnix\WP_Simple_Logger\Handlers\Abstract_Handler;
use WPTechnix\WP_Simple_Logger\Log_Entry;
use WPTechnix\WP_Simple_Logger\Formatters\Line_Formatter;
use Psr\Log\LogLevel;

class Slack_Handler extends Abstract_Handler {
    private string $webhook_url;
    private array $buffer = [];

    public function __construct(string $webhook_url, string $min_level = LogLevel::ERROR) {
        parent::__construct($min_level);
        $this->webhook_url = $webhook_url;
        
        // Use a simple, clean formatter by default for Slack messages.
        if (null === $this->formatter) {
            $this->formatter = new Line_Formatter(
                "[%level_name%] %message% %context%", 
                true
            );
        }
    }

    public function handle(Log_Entry $entry): bool {
        // Format the message and add it to the buffer.
        $this->buffer[] = $this->formatter->format($entry);
        return true;
    }

    public function flush(): void {
        if (empty($this->buffer)) {
            return;
        }

        $message = implode("\n", $this->buffer);
        
        wp_remote_post($this->webhook_url, [
            'body' => wp_json_encode(['text' => "```{$message}```"]),
            'headers' => ['Content-Type' => 'application/json'],
        ]);
        
        $this->buffer = [];
    }
}

// Usage:
// $slack_handler = new Slack_Handler('https://hooks.slack.com/services/...');
// $manager->add_handler($slack_handler);

Creating a Custom Formatter

To create a custom formatter, implement the Formatter_Interface.

  1. Create a class that implements \WPTechnix\WP_Simple_Logger\Contracts\Formatter_Interface.
  2. Implement the format(Log_Entry $entry): string method.

Example: A Simple Message-Only Formatter

<?php
use WPTechnix\WP_Simple_Logger\Contracts\Formatter_Interface;
use WPTechnix\WP_Simple_Logger\Log_Entry;

class Simple_Message_Formatter implements Formatter_Interface {
    public function format(Log_Entry $entry): string {
        return strtoupper($entry->get_level_name()) . ': ' . $entry->get_message() . "\n";
    }
}

Best Practices

  • Centralize Initialization: Configure your Manager and handlers in one central place (like a service container or a dedicated bootstrap function) to ensure consistency across your application.
  • Use Channels Effectively: Adopt a clear and consistent naming convention for your channels. This makes filtering and debugging much easier.
  • Be Mindful of Sensitive Data: Avoid logging passwords, API keys, personal user information, or other sensitive data. If you must log potentially sensitive data, consider writing a custom formatter to sanitize or redact it before it's stored.
  • Use Appropriate Log Levels: Use DEBUG for verbose development information, INFO for routine events, WARNING for non-critical issues, and ERROR/CRITICAL for problems that require immediate attention. This makes level-based filtering effective.
  • Leverage Buffering: For high-traffic sites, handlers like Database_Handler and File_Handler benefit from a non-zero buffer limit. This reduces the number of I/O operations by batching writes.

Edge Cases & Limitations

  • Fatal Errors: If a PHP fatal error occurs that prevents WordPress's shutdown hook from running, buffered logs may be lost. This is a fundamental limitation of PHP's execution model.
  • wp_die(): The library automatically hooks into wp_die to flush logs before execution terminates, so logs from AJAX handlers or form submissions that end in wp_die() should be saved correctly.
Clone this wiki locally