PHPget_error_context()自定义函数

简介

get_error_context() 是一个自定义的PHP函数概念,用于在错误发生时获取详细的上下文信息。虽然PHP没有内置这个函数,但我们可以创建自己的实现,用于收集错误发生时的环境、变量、调用栈等详细信息。

注意:这不是PHP内置函数,而是一个自定义函数概念。PHP的错误处理器(通过set_error_handler()设置)会接收到$errcontext参数,但在PHP 7.2.0中已弃用。我们可以创建自己的上下文收集函数。
注意:在PHP 7.2.0及更高版本中,错误处理器的$errcontext参数已被弃用。如果需要获取错误上下文,应该使用debug_backtrace()get_defined_vars()等函数。

为什么需要错误上下文信息?

更好的调试

了解错误发生时变量的值、调用栈、环境信息,能够更快地定位和修复问题。

错误重现

详细的上下文信息有助于重现错误,特别是在生产环境中难以复现的问题。

日志分析

结构化的上下文信息便于日志分析和错误模式识别。

用户支持

在用户报告错误时,上下文信息能帮助技术支持人员更快理解问题。

函数设计

我们可以设计一个get_error_context()函数,它收集错误发生时的各种上下文信息。

array get_error_context(array $options = [])

参数说明:

参数 类型 默认值 描述
$options array [] 配置选项,控制收集哪些上下文信息。

返回值:

array - 包含错误上下文信息的关联数组。

示例实现

示例1:基本实现

实现一个基本的get_error_context()函数:

<?php
/**
 * 获取错误上下文信息
 *
 * @param array $options 配置选项
 * @return array
 */
function get_error_context(array $options = []) {
    $defaultOptions = [
        'include_backtrace' => true,
        'include_vars' => true,
        'include_env' => true,
        'include_request' => true,
        'include_session' => true,
        'include_cookies' => true,
        'backtrace_limit' => 5,
        'var_filter' => null, // 回调函数,用于过滤敏感变量
    ];

    $options = array_merge($defaultOptions, $options);

    $context = [
        'timestamp' => date('Y-m-d H:i:s'),
        'memory_usage' => memory_get_usage(true),
        'memory_peak' => memory_get_peak_usage(true),
    ];

    // 收集回溯信息
    if ($options['include_backtrace']) {
        $context['backtrace'] = get_backtrace_info($options['backtrace_limit']);
    }

    // 收集变量信息
    if ($options['include_vars']) {
        $context['variables'] = get_variables_info($options['var_filter']);
    }

    // 收集环境信息
    if ($options['include_env']) {
        $context['environment'] = get_environment_info();
    }

    // 收集请求信息
    if ($options['include_request'] && php_sapi_name() !== 'cli') {
        $context['request'] = get_request_info();
    }

    // 收集会话信息
    if ($options['include_session'] && session_status() === PHP_SESSION_ACTIVE) {
        $context['session'] = get_session_info();
    }

    // 收集Cookie信息
    if ($options['include_cookies'] && !empty($_COOKIE)) {
        $context['cookies'] = get_cookies_info();
    }

    return $context;
}

/**
 * 获取回溯信息
 */
function get_backtrace_info($limit = 5) {
    $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit + 2);

    // 移除get_backtrace_info和get_error_context的调用
    array_shift($backtrace); // 移除get_backtrace_info
    array_shift($backtrace); // 移除get_error_context

    $formatted = [];
    foreach ($backtrace as $i => $trace) {
        $formatted[] = [
            'file' => $trace['file'] ?? 'unknown',
            'line' => $trace['line'] ?? 0,
            'function' => $trace['function'] ?? 'unknown',
            'class' => $trace['class'] ?? null,
            'type' => $trace['type'] ?? null,
            'args' => isset($trace['args']) ? format_args($trace['args']) : [],
        ];
    }

    return $formatted;
}

/**
 * 获取变量信息
 */
function get_variables_info($filter = null) {
    $vars = get_defined_vars();

    // 应用过滤器
    if (is_callable($filter)) {
        $vars = $filter($vars);
    }

    return $vars;
}

/**
 * 获取环境信息
 */
function get_environment_info() {
    return [
        'php_version' => PHP_VERSION,
        'php_sapi' => php_sapi_name(),
        'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? null,
        'server_name' => $_SERVER['SERVER_NAME'] ?? null,
        'document_root' => $_SERVER['DOCUMENT_ROOT'] ?? null,
        'script_filename' => $_SERVER['SCRIPT_FILENAME'] ?? null,
        'remote_addr' => $_SERVER['REMOTE_ADDR'] ?? null,
        'request_time' => $_SERVER['REQUEST_TIME'] ?? date('Y-m-d H:i:s'),
        'timezone' => date_default_timezone_get(),
    ];
}

/**
 * 获取请求信息
 */
function get_request_info() {
    return [
        'method' => $_SERVER['REQUEST_METHOD'] ?? 'CLI',
        'uri' => $_SERVER['REQUEST_URI'] ?? null,
        'query_string' => $_SERVER['QUERY_STRING'] ?? null,
        'headers' => getallheaders(),
        'get' => $_GET,
        'post' => $_POST,
        'files' => $_FILES,
    ];
}

/**
 * 获取会话信息
 */
function get_session_info() {
    return isset($_SESSION) ? $_SESSION : [];
}

/**
 * 获取Cookie信息
 */
function get_cookies_info() {
    return $_COOKIE;
}

/**
 * 格式化参数
 */
function format_args($args, $max_length = 100) {
    $formatted = [];

    foreach ($args as $arg) {
        if (is_object($arg)) {
            $formatted[] = get_class($arg) . ' object';
        } elseif (is_array($arg)) {
            $formatted[] = 'Array(' . count($arg) . ')';
        } elseif (is_resource($arg)) {
            $formatted[] = 'Resource(' . get_resource_type($arg) . ')';
        } elseif (is_string($arg)) {
            if (strlen($arg) > $max_length) {
                $arg = substr($arg, 0, $max_length) . '...';
            }
            $formatted[] = '"' . htmlspecialchars($arg) . '"';
        } else {
            $formatted[] = var_export($arg, true);
        }
    }

    return $formatted;
}

/**
 * 过滤敏感变量
 */
function filter_sensitive_vars($vars) {
    $sensitive_keys = ['password', 'passwd', 'pwd', 'secret', 'token', 'key', 'credit_card', 'cc_number'];

    foreach ($vars as $key => $value) {
        foreach ($sensitive_keys as $sensitive) {
            if (stripos($key, $sensitive) !== false) {
                $vars[$key] = '[FILTERED]';
                break;
            }
        }

        // 递归处理数组
        if (is_array($value)) {
            $vars[$key] = filter_sensitive_vars($value);
        }
    }

    return $vars;
}

// 使用示例
echo "<h4>测试get_error_context()基本实现:</h4>";

// 设置一些测试数据
$_GET['page'] = 1;
$_POST['username'] = 'testuser';
$_POST['password'] = 'secret123'; // 敏感数据
$testVar = '测试变量';

// 获取上下文信息
$context = get_error_context([
    'include_backtrace' => true,
    'include_vars' => true,
    'include_env' => true,
    'include_request' => true,
    'backtrace_limit' => 3,
    'var_filter' => 'filter_sensitive_vars',
]);

echo "<pre>" . htmlspecialchars(print_r($context, true)) . "</pre>";

// 测试在函数中获取上下文
function test_function() {
    $localVar = '局部变量';
    $context = get_error_context(['backtrace_limit' => 2]);
    return $context;
}

echo "<h4>在函数中获取上下文:</h4>";
$funcContext = test_function();
echo "<pre>" . htmlspecialchars(print_r($funcContext['backtrace'], true)) . "</pre>";

示例2:在错误处理器中使用

演示如何在自定义错误处理器中使用get_error_context()

<?php
// 包含上一个示例中的get_error_context()函数
// 这里假设get_error_context()和相关函数已定义

/**
 * 自定义错误处理器
 */
function custom_error_handler($errno, $errstr, $errfile, $errline) {
    // 获取错误上下文
    $context = get_error_context([
        'include_backtrace' => true,
        'include_vars' => true,
        'include_env' => true,
        'include_request' => true,
        'backtrace_limit' => 10,
        'var_filter' => 'filter_sensitive_vars',
    ]);

    // 构建错误信息
    $error = [
        'type' => get_error_type_name($errno),
        'message' => $errstr,
        'file' => $errfile,
        'line' => $errline,
        'timestamp' => date('Y-m-d H:i:s'),
        'context' => $context,
    ];

    // 记录错误日志
    log_error($error);

    // 根据环境显示错误
    if (getenv('APP_ENV') === 'development') {
        display_debug_error($error);
    }

    // 对于致命错误,不要返回true
    if (in_array($errno, [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        return false;
    }

    return true; // 阻止PHP默认处理器
}

/**
 * 获取错误类型名称
 */
function get_error_type_name($type) {
    $types = [
        1 => 'E_ERROR',
        2 => 'E_WARNING',
        4 => 'E_PARSE',
        8 => 'E_NOTICE',
        16 => 'E_CORE_ERROR',
        32 => 'E_CORE_WARNING',
        64 => 'E_COMPILE_ERROR',
        128 => 'E_COMPILE_WARNING',
        256 => 'E_USER_ERROR',
        512 => 'E_USER_WARNING',
        1024 => 'E_USER_NOTICE',
        2048 => 'E_STRICT',
        4096 => 'E_RECOVERABLE_ERROR',
        8192 => 'E_DEPRECATED',
        16384 => 'E_USER_DEPRECATED',
    ];

    return isset($types[$type]) ? $types[$type] : "UNKNOWN($type)";
}

/**
 * 记录错误日志
 */
function log_error($error) {
    $logFile = 'logs/errors.log';

    // 确保目录存在
    $logDir = dirname($logFile);
    if (!is_dir($logDir)) {
        mkdir($logDir, 0755, true);
    }

    $logEntry = json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n";
    file_put_contents($logFile, $logEntry, FILE_APPEND);
}

/**
 * 显示调试错误
 */
function display_debug_error($error) {
    echo "<div style='background:#f8f9fa; padding:20px; margin:20px 0; border:1px solid #ddd; font-family:monospace;'>";
    echo "<h3 style='color:#dc3545; margin-top:0;'>错误详情</h3>";

    echo "<table style='width:100%; border-collapse:collapse;'>";
    echo "<tr><td style='width:120px; padding:5px; font-weight:bold;'>类型:</td><td style='padding:5px;'>" . $error['type'] . "</td></tr>";
    echo "<tr><td style='padding:5px; font-weight:bold;'>消息:</td><td style='padding:5px;'>" . htmlspecialchars($error['message']) . "</td></tr>";
    echo "<tr><td style='padding:5px; font-weight:bold;'>文件:</td><td style='padding:5px;'>" . $error['file'] . "</td></tr>";
    echo "<tr><td style='padding:5px; font-weight:bold;'>行号:</td><td style='padding:5px;'>" . $error['line'] . "</td></tr>";
    echo "</table>";

    echo "</div>";
}

// 设置环境
putenv('APP_ENV=development');

// 设置自定义错误处理器
set_error_handler('custom_error_handler', E_ALL);

// 使用示例
echo "<h4>测试自定义错误处理器:</h4>";

// 设置一些测试数据
$_GET['id'] = 123;
$_POST['email'] = 'user@example.com';
$config = ['db_host' => 'localhost', 'db_name' => 'test'];

// 触发不同类型的错误
echo "<strong>触发警告:</strong><br>";
$result = 10 / 0;  // 除以零警告

echo "<br><strong>触发通知:</strong><br>";
echo $undefinedVariable;  // 使用未定义变量

echo "<br><strong>触发用户错误:</strong><br>";
trigger_error("这是一个用户自定义错误", E_USER_ERROR);

echo "<div class='alert alert-info'>";
echo "查看 logs/errors.log 文件获取详细错误日志(包含上下文信息)";
echo "</div>";

示例3:在异常处理器中使用

演示如何在异常处理器中使用get_error_context()

<?php
// 包含get_error_context()函数
// 这里假设get_error_context()和相关函数已定义

/**
 * 异常上下文收集器
 */
class ExceptionContextCollector {
    /**
     * 收集异常上下文
     */
    public static function collect($exception, $options = []) {
        $defaultOptions = [
            'include_exception' => true,
            'include_backtrace' => true,
            'include_vars' => true,
            'include_code_snippet' => true,
            'code_snippet_lines' => 5,
        ];

        $options = array_merge($defaultOptions, $options);

        $context = get_error_context($options);

        // 添加异常特定信息
        if ($options['include_exception']) {
            $context['exception'] = [
                'class' => get_class($exception),
                'message' => $exception->getMessage(),
                'code' => $exception->getCode(),
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
                'previous' => $exception->getPrevious() ? get_class($exception->getPrevious()) : null,
            ];
        }

        // 添加代码片段
        if ($options['include_code_snippet'] && file_exists($exception->getFile())) {
            $context['code_snippet'] = self::getCodeSnippet(
                $exception->getFile(),
                $exception->getLine(),
                $options['code_snippet_lines']
            );
        }

        return $context;
    }

    /**
     * 获取代码片段
     */
    private static function getCodeSnippet($file, $line, $lines = 5) {
        if (!file_exists($file)) {
            return null;
        }

        $source = file($file);
        $start = max(0, $line - $lines - 1);
        $end = min(count($source), $line + $lines);

        $snippet = [];
        for ($i = $start; $i < $end; $i++) {
            $snippet[$i + 1] = [
                'line' => $i + 1,
                'code' => rtrim($source[$i]),
                'current' => ($i + 1) == $line,
            ];
        }

        return $snippet;
    }

    /**
     * 设置异常日志记录器
     */
    public static function setExceptionLogger($options = []) {
        set_exception_handler(function($exception) use ($options) {
            $context = self::collect($exception, $options);
            self::logException($exception, $context);

            // 重新抛出异常
            throw $exception;
        });
    }

    /**
     * 记录异常
     */
    private static function logException($exception, $context) {
        $logFile = 'logs/exceptions.log';

        // 确保目录存在
        $logDir = dirname($logFile);
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }

        $logData = [
            'timestamp' => date('Y-m-d H:i:s'),
            'exception' => get_class($exception),
            'message' => $exception->getMessage(),
            'file' => $exception->getFile(),
            'line' => $exception->getLine(),
            'context' => $context,
        ];

        $logEntry = json_encode($logData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n";
        file_put_contents($logFile, $logEntry, FILE_APPEND);
    }
}

// 使用示例
echo "<h4>测试异常上下文收集:</h4>";

// 设置异常日志记录器
ExceptionContextCollector::setExceptionLogger([
    'include_code_snippet' => true,
    'code_snippet_lines' => 3,
    'include_backtrace' => true,
    'backtrace_limit' => 5,
]);

// 定义自定义异常
class ValidationException extends Exception {
    private $errors = [];

    public function __construct($message, $errors = [], $code = 0, Exception $previous = null) {
        $this->errors = $errors;
        parent::__construct($message, $code, $previous);
    }

    public function getErrors() {
        return $this->errors;
    }
}

// 测试函数
function validateUser($data) {
    if (empty($data['username'])) {
        throw new ValidationException("用户名不能为空", ['username' => 'required']);
    }

    if (strlen($data['username']) < 3) {
        throw new ValidationException("用户名至少3个字符", ['username' => 'min_length']);
    }

    return true;
}

// 测试异常
try {
    $userData = ['username' => 'ab']; // 无效的用户名
    validateUser($userData);
} catch (ValidationException $e) {
    echo "<div class='alert alert-warning'>";
    echo "验证异常: " . $e->getMessage();
    echo "</div>";

    // 收集上下文但不记录(因为异常已被捕获)
    $context = ExceptionContextCollector::collect($e, [
        'include_code_snippet' => true,
        'code_snippet_lines' => 5,
    ]);

    echo "<h5>异常上下文:</h5>";
    echo "<pre style='max-height:300px; overflow:auto;'>" .
         htmlspecialchars(print_r($context, true)) . "</pre>";
}

// 这个异常会被异常处理器记录
function processOrder($orderId) {
    if ($orderId <= 0) {
        throw new InvalidArgumentException("无效的订单ID: " . $orderId);
    }

    // 模拟数据库操作
    if (!is_numeric($orderId)) {
        throw new RuntimeException("数据库查询失败: 订单不存在");
    }

    return ['id' => $orderId, 'status' => 'processing'];
}

// 触发未捕获的异常
processOrder(-1);

echo "<div class='alert alert-info'>";
echo "查看 logs/exceptions.log 文件获取异常日志(包含完整上下文)";
echo "</div>";

示例4:上下文感知的调试工具

创建一个上下文感知的调试工具,可以在任意位置获取当前上下文:

<?php
/**
 * 上下文感知的调试工具
 */
class ContextAwareDebugger {
    private static $snapshots = [];
    private static $enabled = true;

    /**
     * 启用/禁用调试器
     */
    public static function enable($enabled = true) {
        self::$enabled = $enabled;
    }

    /**
     * 获取当前上下文快照
     */
    public static function snapshot($label = null, $options = []) {
        if (!self::$enabled) {
            return null;
        }

        $context = get_error_context($options);

        $snapshot = [
            'label' => $label ?: 'Snapshot ' . (count(self::$snapshots) + 1),
            'timestamp' => microtime(true),
            'context' => $context,
        ];

        self::$snapshots[] = $snapshot;

        return $snapshot;
    }

    /**
     * 获取所有快照
     */
    public static function getSnapshots() {
        return self::$snapshots;
    }

    /**
     * 清除所有快照
     */
    public static function clearSnapshots() {
        self::$snapshots = [];
    }

    /**
     * 在代码中设置检查点
     */
    public static function checkpoint($label = null, $condition = null) {
        if (!self::$enabled) {
            return;
        }

        $snapshot = self::snapshot($label, [
            'include_backtrace' => true,
            'backtrace_limit' => 3,
        ]);

        // 如果提供了条件,检查并记录
        if ($condition !== null && !$condition) {
            self::logCheckpointFailure($snapshot, $condition);
        }

        return $snapshot;
    }

    /**
     * 记录检查点失败
     */
    private static function logCheckpointFailure($snapshot, $condition) {
        $logFile = 'logs/checkpoints.log';

        $logData = [
            'timestamp' => date('Y-m-d H:i:s'),
            'checkpoint' => $snapshot['label'],
            'condition' => var_export($condition, true),
            'context' => $snapshot['context'],
        ];

        $logEntry = json_encode($logData, JSON_PRETTY_PRINT) . "\n";
        file_put_contents($logFile, $logEntry, FILE_APPEND);
    }

    /**
     * 跟踪变量变化
     */
    public static function trace($variable, $name = null) {
        if (!self::$enabled) {
            return;
        }

        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
        $caller = $backtrace[1] ?? $backtrace[0];

        $trace = [
            'timestamp' => microtime(true),
            'variable' => $name ?: 'unnamed',
            'value' => self::formatVariable($variable),
            'type' => gettype($variable),
            'caller' => [
                'file' => $caller['file'] ?? 'unknown',
                'line' => $caller['line'] ?? 0,
                'function' => $caller['function'] ?? 'unknown',
            ],
        ];

        self::$snapshots[] = [
            'label' => 'Variable Trace: ' . ($name ?: 'unnamed'),
            'timestamp' => $trace['timestamp'],
            'context' => ['trace' => $trace],
        ];

        return $trace;
    }

    /**
     * 格式化变量
     */
    private static function formatVariable($var, $maxDepth = 2, $depth = 0) {
        if ($depth >= $maxDepth) {
            return '...';
        }

        if (is_object($var)) {
            return get_class($var) . ' object';
        } elseif (is_array($var)) {
            $result = [];
            foreach ($var as $key => $value) {
                $result[$key] = self::formatVariable($value, $maxDepth, $depth + 1);
            }
            return $result;
        } elseif (is_resource($var)) {
            return 'Resource(' . get_resource_type($var) . ')';
        } elseif (is_string($var)) {
            if (strlen($var) > 100) {
                $var = substr($var, 0, 100) . '...';
            }
            return $var;
        } else {
            return var_export($var, true);
        }
    }

    /**
     * 生成调试报告
     */
    public static function generateReport() {
        if (empty(self::$snapshots)) {
            return ['message' => 'No snapshots available'];
        }

        $report = [
            'generated_at' => date('Y-m-d H:i:s'),
            'total_snapshots' => count(self::$snapshots),
            'snapshots' => self::$snapshots,
            'memory_usage' => memory_get_usage(true),
            'memory_peak' => memory_get_peak_usage(true),
            'execution_time' => microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'],
        ];

        return $report;
    }
}

// 使用示例
echo "<h4>测试ContextAwareDebugger:</h4>";

// 启用调试器
ContextAwareDebugger::enable(true);

// 模拟应用程序流程
echo "<strong>模拟应用程序执行流程:</strong><br>";

// 检查点1:应用程序启动
ContextAwareDebugger::checkpoint('App Startup');

// 设置一些变量
$config = ['debug' => true, 'environment' => 'development'];
$user = ['id' => 123, 'name' => 'John Doe', 'email' => 'john@example.com'];

// 跟踪变量
ContextAwareDebugger::trace($config, 'config');
ContextAwareDebugger::trace($user, 'user');

// 检查点2:处理请求
ContextAwareDebugger::checkpoint('Process Request', !empty($_GET));

// 模拟处理
function processData($data) {
    // 检查点:在处理函数内部
    ContextAwareDebugger::checkpoint('Inside processData');

    if (empty($data)) {
        return false;
    }

    return array_map('strtoupper', $data);
}

$data = ['item1', 'item2', 'item3'];
$processed = processData($data);

ContextAwareDebugger::trace($processed, 'processed_data');

// 检查点3:处理完成
ContextAwareDebugger::checkpoint('Processing Complete', $processed !== false);

// 生成报告
$report = ContextAwareDebugger::generateReport();

echo "<div class='alert alert-success'>";
echo "生成了 " . $report['total_snapshots'] . " 个上下文快照";
echo "</div>";

echo "<h5>快照列表:</h5>";
foreach ($report['snapshots'] as $i => $snapshot) {
    echo "<div style='background:#f8f9fa; padding:10px; margin:5px; border-left:4px solid #007bff;'>";
    echo "<strong>" . ($i + 1) . ". " . $snapshot['label'] . "</strong><br>";
    echo "时间: " . date('H:i:s', (int)$snapshot['timestamp']) . "<br>";

    if (isset($snapshot['context']['trace'])) {
        echo "变量: " . $snapshot['context']['trace']['variable'] . " = " .
             htmlspecialchars(print_r($snapshot['context']['trace']['value'], true));
    }

    echo "</div>";
}

// 获取详细报告
echo "<h5>详细调试报告:</h5>";
echo "<pre style='max-height:400px; overflow:auto;'>" .
     htmlspecialchars(print_r($report, true)) . "</pre>";

示例5:生产环境错误上下文收集

演示在生产环境中安全地收集错误上下文:

<?php
/**
 * 生产环境错误上下文收集器
 */
class ProductionErrorCollector {
    private static $config = [
        'enabled' => true,
        'log_file' => 'logs/production_errors.log',
        'max_log_size' => 10485760, // 10MB
        'max_log_files' => 5,
        'include_stack_trace' => true,
        'include_request_data' => true,
        'include_session_data' => false, // 生产环境通常不记录会话数据
        'include_cookie_data' => false,  // 生产环境通常不记录Cookie数据
        'filter_sensitive_data' => true,
        'sensitive_patterns' => [
            '/password/i',
            '/passwd/i',
            '/pwd/i',
            '/secret/i',
            '/token/i',
            '/key/i',
            '/credit.?card/i',
            '/cc.?number/i',
            '/cvv/i',
            '/ssn/i',
            '/social.?security/i',
        ],
        'sanitize_paths' => true,
        'obfuscate_ips' => true,
    ];

    /**
     * 初始化
     */
    public static function init($config = []) {
        self::$config = array_merge(self::$config, $config);

        if (!self::$config['enabled']) {
            return;
        }

        // 设置错误处理器
        set_error_handler([self::class, 'handleError']);

        // 设置异常处理器
        set_exception_handler([self::class, 'handleException']);

        // 注册关闭函数
        register_shutdown_function([self::class, 'handleShutdown']);
    }

    /**
     * 处理错误
     */
    public static function handleError($errno, $errstr, $errfile, $errline) {
        $context = self::collectContext();

        $error = [
            'type' => 'error',
            'level' => self::getErrorLevelName($errno),
            'message' => $errstr,
            'file' => self::sanitizePath($errfile),
            'line' => $errline,
            'timestamp' => date('c'),
            'context' => $context,
        ];

        self::log($error);

        // 对于非致命错误,返回false让PHP继续处理
        if (!in_array($errno, [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
            return false;
        }

        // 对于致命错误,我们已经记录了,让PHP处理
        return false;
    }

    /**
     * 处理异常
     */
    public static function handleException($exception) {
        $context = self::collectContext();

        $error = [
            'type' => 'exception',
            'exception' => get_class($exception),
            'message' => $exception->getMessage(),
            'code' => $exception->getCode(),
            'file' => self::sanitizePath($exception->getFile()),
            'line' => $exception->getLine(),
            'timestamp' => date('c'),
            'context' => $context,
        ];

        if (self::$config['include_stack_trace']) {
            $error['stack_trace'] = self::sanitizeStackTrace($exception->getTrace());
        }

        self::log($error);

        // 重新抛出异常
        throw $exception;
    }

    /**
     * 处理关闭
     */
    public static function handleShutdown() {
        $error = error_get_last();

        if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
            $context = self::collectContext();

            $log = [
                'type' => 'fatal_error',
                'level' => self::getErrorLevelName($error['type']),
                'message' => $error['message'],
                'file' => self::sanitizePath($error['file']),
                'line' => $error['line'],
                'timestamp' => date('c'),
                'context' => $context,
            ];

            self::log($log);
        }
    }

    /**
     * 收集上下文
     */
    private static function collectContext() {
        $context = [
            'timestamp' => date('c'),
            'memory' => [
                'usage' => memory_get_usage(true),
                'peak' => memory_get_peak_usage(true),
            ],
            'environment' => [
                'php_version' => PHP_VERSION,
                'sapi' => php_sapi_name(),
                'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? null,
            ],
        ];

        // 请求数据
        if (self::$config['include_request_data'] && php_sapi_name() !== 'cli') {
            $context['request'] = self::collectRequestData();
        }

        // 会话数据
        if (self::$config['include_session_data'] && session_status() === PHP_SESSION_ACTIVE) {
            $context['session'] = self::filterSensitiveData($_SESSION ?? []);
        }

        // Cookie数据
        if (self::$config['include_cookie_data'] && !empty($_COOKIE)) {
            $context['cookies'] = self::filterSensitiveData($_COOKIE);
        }

        return $context;
    }

    /**
     * 收集请求数据
     */
    private static function collectRequestData() {
        $request = [
            'method' => $_SERVER['REQUEST_METHOD'] ?? 'CLI',
            'uri' => $_SERVER['REQUEST_URI'] ?? null,
        ];

        // 清理URI中的敏感信息
        if (self::$config['sanitize_paths'] && isset($request['uri'])) {
            $request['uri'] = self::sanitizePath($request['uri']);
        }

        // GET参数
        if (!empty($_GET)) {
            $request['get'] = self::filterSensitiveData($_GET);
        }

        // POST参数
        if (!empty($_POST)) {
            $request['post'] = self::filterSensitiveData($_POST);
        }

        // 头部信息
        $headers = [];
        foreach ($_SERVER as $key => $value) {
            if (strpos($key, 'HTTP_') === 0) {
                $header = str_replace('_', '-', strtolower(substr($key, 5)));
                $headers[$header] = $value;
            }
        }

        if (!empty($headers)) {
            $request['headers'] = $headers;
        }

        // IP地址
        if (self::$config['obfuscate_ips']) {
            $request['ip'] = self::obfuscateIp($_SERVER['REMOTE_ADDR'] ?? null);
        } else {
            $request['ip'] = $_SERVER['REMOTE_ADDR'] ?? null;
        }

        return $request;
    }

    /**
     * 过滤敏感数据
     */
    private static function filterSensitiveData($data) {
        if (!self::$config['filter_sensitive_data']) {
            return $data;
        }

        if (!is_array($data)) {
            return $data;
        }

        $filtered = [];
        foreach ($data as $key => $value) {
            $shouldFilter = false;

            // 检查键名是否匹配敏感模式
            foreach (self::$config['sensitive_patterns'] as $pattern) {
                if (preg_match($pattern, $key)) {
                    $shouldFilter = true;
                    break;
                }
            }

            if ($shouldFilter) {
                $filtered[$key] = '[FILTERED]';
            } elseif (is_array($value)) {
                $filtered[$key] = self::filterSensitiveData($value);
            } else {
                $filtered[$key] = $value;
            }
        }

        return $filtered;
    }

    /**
     * 清理路径
     */
    private static function sanitizePath($path) {
        if (!self::$config['sanitize_paths'] || empty($path)) {
            return $path;
        }

        // 移除文档根路径
        $docRoot = $_SERVER['DOCUMENT_ROOT'] ?? '';
        if ($docRoot && strpos($path, $docRoot) === 0) {
            $path = '[DOCROOT]' . substr($path, strlen($docRoot));
        }

        // 移除用户名
        $path = preg_replace('/\/home\/[^\/]+\//', '/home/[USER]/', $path);

        return $path;
    }

    /**
     * 清理堆栈跟踪
     */
    private static function sanitizeStackTrace($trace) {
        $sanitized = [];

        foreach ($trace as $frame) {
            $sanitizedFrame = $frame;

            if (isset($frame['file'])) {
                $sanitizedFrame['file'] = self::sanitizePath($frame['file']);
            }

            // 清理参数中的敏感数据
            if (isset($frame['args'])) {
                $sanitizedFrame['args'] = self::filterSensitiveData($frame['args']);
            }

            $sanitized[] = $sanitizedFrame;
        }

        return $sanitized;
    }

    /**
     * 混淆IP地址
     */
    private static function obfuscateIp($ip) {
        if (empty($ip)) {
            return null;
        }

        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            // IPv4: 保留前两个字节
            $parts = explode('.', $ip);
            if (count($parts) === 4) {
                return $parts[0] . '.' . $parts[1] . '.x.x';
            }
        } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            // IPv6: 简化
            return substr($ip, 0, 8) . '...';
        }

        return $ip;
    }

    /**
     * 获取错误级别名称
     */
    private static function getErrorLevelName($level) {
        $levels = [
            1 => 'E_ERROR',
            2 => 'E_WARNING',
            4 => 'E_PARSE',
            8 => 'E_NOTICE',
            16 => 'E_CORE_ERROR',
            32 => 'E_CORE_WARNING',
            64 => 'E_COMPILE_ERROR',
            128 => 'E_COMPILE_WARNING',
            256 => 'E_USER_ERROR',
            512 => 'E_USER_WARNING',
            1024 => 'E_USER_NOTICE',
            2048 => 'E_STRICT',
            4096 => 'E_RECOVERABLE_ERROR',
            8192 => 'E_DEPRECATED',
            16384 => 'E_USER_DEPRECATED',
        ];

        return $levels[$level] ?? "UNKNOWN($level)";
    }

    /**
     * 记录错误
     */
    private static function log($data) {
        $logFile = self::$config['log_file'];

        // 确保目录存在
        $logDir = dirname($logFile);
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }

        // 检查日志轮转
        self::rotateLogIfNeeded();

        $logEntry = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n";
        file_put_contents($logFile, $logEntry, FILE_APPEND);
    }

    /**
     * 日志轮转
     */
    private static function rotateLogIfNeeded() {
        $logFile = self::$config['log_file'];

        if (!file_exists($logFile)) {
            return;
        }

        $maxSize = self::$config['max_log_size'];
        $maxFiles = self::$config['max_log_files'];

        if (filesize($logFile) < $maxSize) {
            return;
        }

        // 轮转日志文件
        for ($i = $maxFiles - 1; $i > 0; $i--) {
            $oldFile = $logFile . '.' . $i;
            $newFile = $logFile . '.' . ($i + 1);

            if (file_exists($oldFile)) {
                if ($i === $maxFiles - 1 && file_exists($newFile)) {
                    unlink($newFile);
                }
                rename($oldFile, $newFile);
            }
        }

        rename($logFile, $logFile . '.1');
    }
}

// 使用示例
echo "<h4>测试生产环境错误上下文收集:</h4>";

// 初始化生产环境错误收集器
ProductionErrorCollector::init([
    'log_file' => 'logs/prod_errors.log',
    'include_session_data' => false,
    'include_cookie_data' => false,
    'filter_sensitive_data' => true,
    'obfuscate_ips' => true,
]);

echo "<div class='alert alert-success'>";
echo "生产环境错误收集器已初始化";
echo "</div>";

// 模拟生产环境错误
echo "<strong>触发测试错误:</strong><br>";

// 设置一些测试数据(包含敏感信息)
$_GET['page'] = 1;
$_POST['username'] = 'admin';
$_POST['password'] = 'SuperSecret123!'; // 敏感数据
$_SERVER['REMOTE_ADDR'] = '192.168.1.100';
$_SERVER['DOCUMENT_ROOT'] = '/var/www/html';

// 触发错误
trigger_error("测试生产环境错误处理", E_USER_WARNING);

echo "<div class='alert alert-info'>";
echo "查看 logs/prod_errors.log 文件获取错误日志(已过滤敏感信息)";
echo "</div>";

// 测试异常
try {
    throw new RuntimeException("测试生产环境异常");
} catch (Exception $e) {
    echo "<div class='alert alert-warning'>";
    echo "异常已被捕获: " . $e->getMessage();
    echo "</div>";
}

// 模拟文件系统错误
@file_get_contents('/nonexistent/file.txt');

echo "<div class='alert alert-info'>";
echo "所有错误都已记录到日志文件,敏感信息已被过滤";
echo "</div>";

示例6:完整的错误上下文工具包

创建一个完整的错误上下文工具包,包含各种实用功能:

<?php
/**
 * 完整的错误上下文工具包
 */
class ErrorContextToolkit {
    /**
     * 获取错误上下文报告
     */
    public static function getReport($options = []) {
        $defaultOptions = [
            'level' => 'normal', // 'minimal', 'normal', 'detailed', 'debug'
            'include' => [
                'basic' => true,
                'environment' => true,
                'request' => true,
                'session' => false,
                'cookies' => false,
                'server' => false,
                'backtrace' => true,
                'variables' => false,
                'constants' => false,
                'loaded_extensions' => false,
                'ini_settings' => false,
                'database' => false,
                'cache' => false,
                'queue' => false,
            ],
            'filters' => [],
            'formatters' => [],
        ];

        $options = array_merge_recursive($defaultOptions, $options);

        $report = [];

        // 基本上下文
        if ($options['include']['basic']) {
            $report['basic'] = self::getBasicContext();
        }

        // 环境信息
        if ($options['include']['environment']) {
            $report['environment'] = self::getEnvironmentContext();
        }

        // 请求信息
        if ($options['include']['request'] && php_sapi_name() !== 'cli') {
            $report['request'] = self::getRequestContext();
        }

        // 会话信息
        if ($options['include']['session'] && session_status() === PHP_SESSION_ACTIVE) {
            $report['session'] = self::getSessionContext();
        }

        // Cookie信息
        if ($options['include']['cookies'] && !empty($_COOKIE)) {
            $report['cookies'] = self::getCookieContext();
        }

        // 服务器信息
        if ($options['include']['server']) {
            $report['server'] = self::getServerContext();
        }

        // 回溯信息
        if ($options['include']['backtrace']) {
            $report['backtrace'] = self::getBacktraceContext($options['level']);
        }

        // 变量信息
        if ($options['include']['variables']) {
            $report['variables'] = self::getVariableContext($options['level']);
        }

        // 常量信息
        if ($options['include']['constants']) {
            $report['constants'] = self::getConstantContext();
        }

        // 加载的扩展
        if ($options['include']['loaded_extensions']) {
            $report['loaded_extensions'] = get_loaded_extensions();
        }

        // INI设置
        if ($options['include']['ini_settings']) {
            $report['ini_settings'] = self::getIniContext();
        }

        // 数据库上下文
        if ($options['include']['database']) {
            $report['database'] = self::getDatabaseContext();
        }

        // 缓存上下文
        if ($options['include']['cache']) {
            $report['cache'] = self::getCacheContext();
        }

        // 队列上下文
        if ($options['include']['queue']) {
            $report['queue'] = self::getQueueContext();
        }

        // 应用过滤器
        foreach ($options['filters'] as $filter) {
            if (is_callable($filter)) {
                $report = $filter($report);
            }
        }

        // 应用格式化器
        foreach ($options['formatters'] as $formatter) {
            if (is_callable($formatter)) {
                $report = $formatter($report);
            }
        }

        return $report;
    }

    /**
     * 获取基本上下文
     */
    private static function getBasicContext() {
        return [
            'timestamp' => date('c'),
            'microtime' => microtime(true),
            'memory_usage' => memory_get_usage(true),
            'memory_peak' => memory_get_peak_usage(true),
            'included_files' => get_included_files(),
        ];
    }

    /**
     * 获取环境上下文
     */
    private static function getEnvironmentContext() {
        return [
            'php_version' => PHP_VERSION,
            'php_sapi' => php_sapi_name(),
            'os' => PHP_OS,
            'architecture' => (PHP_INT_SIZE * 8) . '-bit',
            'timezone' => date_default_timezone_get(),
            'locale' => setlocale(LC_ALL, 0),
            'max_execution_time' => ini_get('max_execution_time'),
            'max_input_time' => ini_get('max_input_time'),
            'memory_limit' => ini_get('memory_limit'),
            'error_reporting' => error_reporting(),
            'display_errors' => ini_get('display_errors'),
            'log_errors' => ini_get('log_errors'),
            'error_log' => ini_get('error_log'),
        ];
    }

    /**
     * 获取请求上下文
     */
    private static function getRequestContext() {
        $request = [
            'method' => $_SERVER['REQUEST_METHOD'] ?? null,
            'scheme' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http',
            'host' => $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? null,
            'port' => $_SERVER['SERVER_PORT'] ?? null,
            'uri' => $_SERVER['REQUEST_URI'] ?? null,
            'query_string' => $_SERVER['QUERY_STRING'] ?? null,
            'script_name' => $_SERVER['SCRIPT_NAME'] ?? null,
            'path_info' => $_SERVER['PATH_INFO'] ?? null,
            'remote_addr' => $_SERVER['REMOTE_ADDR'] ?? null,
            'remote_port' => $_SERVER['REMOTE_PORT'] ?? null,
            'server_addr' => $_SERVER['SERVER_ADDR'] ?? null,
            'server_port' => $_SERVER['SERVER_PORT'] ?? null,
            'request_time' => $_SERVER['REQUEST_TIME'] ?? null,
            'request_time_float' => $_SERVER['REQUEST_TIME_FLOAT'] ?? null,
        ];

        // 头部信息
        $headers = [];
        foreach ($_SERVER as $key => $value) {
            if (strpos($key, 'HTTP_') === 0) {
                $header = str_replace('_', '-', strtolower(substr($key, 5)));
                $headers[$header] = $value;
            }
        }

        if (!empty($headers)) {
            $request['headers'] = $headers;
        }

        // GET参数
        if (!empty($_GET)) {
            $request['get'] = $_GET;
        }

        // POST参数
        if (!empty($_POST)) {
            $request['post'] = $_POST;
        }

        // 文件上传
        if (!empty($_FILES)) {
            $request['files'] = array_keys($_FILES);
        }

        return $request;
    }

    /**
     * 获取会话上下文
     */
    private static function getSessionContext() {
        return [
            'id' => session_id(),
            'name' => session_name(),
            'status' => session_status(),
            'save_path' => session_save_path(),
            'data' => $_SESSION ?? [],
        ];
    }

    /**
     * 获取Cookie上下文
     */
    private static function getCookieContext() {
        return $_COOKIE;
    }

    /**
     * 获取服务器上下文
     */
    private static function getServerContext() {
        $server = [];

        // 收集服务器变量,排除敏感信息
        $exclude = ['HTTP_AUTHORIZATION', 'PHP_AUTH_USER', 'PHP_AUTH_PW', 'PATH', 'PATHEXT'];

        foreach ($_SERVER as $key => $value) {
            if (!in_array($key, $exclude) && !preg_match('/PASS/i', $key)) {
                $server[$key] = $value;
            }
        }

        return $server;
    }

    /**
     * 获取回溯上下文
     */
    private static function getBacktraceContext($level = 'normal') {
        $limit = 0;

        switch ($level) {
            case 'minimal':
                $limit = 3;
                break;
            case 'normal':
                $limit = 10;
                break;
            case 'detailed':
                $limit = 20;
                break;
            case 'debug':
                $limit = 0;
                break;
            default:
                $limit = 10;
        }

        $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit);

        // 移除工具包自身的调用
        $filtered = [];
        foreach ($backtrace as $trace) {
            if (isset($trace['class']) && $trace['class'] === __CLASS__) {
                continue;
            }
            $filtered[] = $trace;
        }

        return $filtered;
    }

    /**
     * 获取变量上下文
     */
    private static function getVariableContext($level = 'normal') {
        $vars = get_defined_vars();

        // 根据级别过滤
        switch ($level) {
            case 'minimal':
                // 只保留全局变量
                $vars = array_intersect_key($vars, $GLOBALS);
                break;
            case 'normal':
                // 移除超全局变量
                unset($vars['GLOBALS']);
                break;
            case 'detailed':
            case 'debug':
                // 包含所有变量
                break;
        }

        return $vars;
    }

    /**
     * 获取常量上下文
     */
    private static function getConstantContext() {
        return get_defined_constants(true);
    }

    /**
     * 获取INI上下文
     */
    private static function getIniContext() {
        $ini = ini_get_all();

        // 分组INI设置
        $grouped = [];
        foreach ($ini as $key => $value) {
            $parts = explode('.', $key);
            $group = count($parts) > 1 ? $parts[0] : 'other';

            if (!isset($grouped[$group])) {
                $grouped[$group] = [];
            }

            $grouped[$group][$key] = $value;
        }

        return $grouped;
    }

    /**
     * 获取数据库上下文
     */
    private static function getDatabaseContext() {
        $context = [];

        // 尝试检测常见的数据库连接
        if (class_exists('PDO')) {
            $context['pdo_drivers'] = PDO::getAvailableDrivers();
        }

        if (function_exists('mysqli_connect')) {
            $context['mysqli'] = [
                'client_version' => mysqli_get_client_version(),
                'client_info' => mysqli_get_client_info(),
            ];
        }

        return $context;
    }

    /**
     * 获取缓存上下文
     */
    private static function getCacheContext() {
        $context = [];

        // 检查常见缓存扩展
        $extensions = ['apc', 'apcu', 'memcached', 'redis', 'xcache'];

        foreach ($extensions as $ext) {
            if (extension_loaded($ext)) {
                $context[$ext] = true;
            }
        }

        return $context;
    }

    /**
     * 获取队列上下文
     */
    private static function getQueueContext() {
        $context = [];

        // 检查常见队列扩展
        if (class_exists('Redis')) {
            $context['redis'] = true;
        }

        if (class_exists('AMQPConnection')) {
            $context['amqp'] = true;
        }

        if (class_exists('GearmanClient')) {
            $context['gearman'] = true;
        }

        return $context;
    }

    /**
     * 格式化报告为字符串
     */
    public static function formatReport($report, $format = 'text') {
        switch ($format) {
            case 'json':
                return json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
            case 'html':
                return self::formatAsHtml($report);
            case 'yaml':
                return self::formatAsYaml($report);
            case 'text':
            default:
                return print_r($report, true);
        }
    }

    /**
     * 格式化为HTML
     */
    private static function formatAsHtml($report) {
        $html = "<div class='error-context-report'>";

        foreach ($report as $section => $data) {
            $html .= "<h3>" . htmlspecialchars($section) . "</h3>";
            $html .= "<pre>" . htmlspecialchars(print_r($data, true)) . "</pre>";
        }

        $html .= "</div>";

        return $html;
    }

    /**
     * 格式化为YAML
     */
    private static function formatAsYaml($report) {
        // 简单的YAML格式化
        $yaml = '';

        foreach ($report as $section => $data) {
            $yaml .= $section . ":\n";

            if (is_array($data)) {
                foreach ($data as $key => $value) {
                    $yaml .= "  " . $key . ": " . self::yamlValue($value, 2) . "\n";
                }
            } else {
                $yaml .= "  " . self::yamlValue($data, 2) . "\n";
            }
        }

        return $yaml;
    }

    /**
     * YAML值格式化
     */
    private static function yamlValue($value, $indent = 0) {
        if (is_array($value)) {
            $result = "\n";
            foreach ($value as $k => $v) {
                $result .= str_repeat(' ', $indent) . $k . ": " . self::yamlValue($v, $indent + 2) . "\n";
            }
            return $result;
        } elseif (is_bool($value)) {
            return $value ? 'true' : 'false';
        } elseif (is_null($value)) {
            return 'null';
        } elseif (is_numeric($value)) {
            return $value;
        } else {
            return '"' . addcslashes($value, '"\\') . '"';
        }
    }
}

// 使用示例
echo "<h4>测试ErrorContextToolkit:</h4>";

// 获取不同级别的报告
echo "<h5>1. 最小化报告:</h5>";
$minimalReport = ErrorContextToolkit::getReport([
    'level' => 'minimal',
    'include' => [
        'basic' => true,
        'environment' => true,
        'request' => true,
        'backtrace' => true,
        'variables' => false,
    ],
]);

echo "<pre style='max-height:200px; overflow:auto;'>" .
     htmlspecialchars(ErrorContextToolkit::formatReport($minimalReport, 'text')) . "</pre>";

echo "<h5>2. 详细报告:</h5>";
$detailedReport = ErrorContextToolkit::getReport([
    'level' => 'detailed',
    'include' => [
        'basic' => true,
        'environment' => true,
        'request' => true,
        'backtrace' => true,
        'variables' => true,
        'constants' => true,
        'loaded_extensions' => true,
    ],
]);

echo "报告大小: " . count($detailedReport) . " 个部分<br>";
echo "<div class='alert alert-info'>";
echo "详细报告包含大量信息,这里不全部显示";
echo "</div>";

echo "<h5>3. JSON格式报告:</h5>";
$jsonReport = ErrorContextToolkit::formatReport($minimalReport, 'json');
echo "<pre style='max-height:200px; overflow:auto;'>" .
     htmlspecialchars($jsonReport) . "</pre>";

echo "<h5>4. 在错误处理器中使用:</h5>";

// 创建自定义错误处理器
set_error_handler(function($errno, $errstr, $errfile, $errline) {
    $context = ErrorContextToolkit::getReport([
        'level' => 'normal',
        'include' => [
            'basic' => true,
            'environment' => true,
            'request' => true,
            'backtrace' => true,
        ],
    ]);

    $error = [
        'type' => 'error',
        'level' => $errno,
        'message' => $errstr,
        'file' => $errfile,
        'line' => $errline,
        'context' => $context,
    ];

    // 记录到文件
    $log = json_encode($error, JSON_PRETTY_PRINT) . "\n";
    file_put_contents('logs/context_errors.log', $log, FILE_APPEND);

    echo "<div class='alert alert-warning'>";
    echo "错误已记录,包含完整上下文信息";
    echo "</div>";

    return true;
});

// 触发错误测试
trigger_error("测试错误上下文收集", E_USER_NOTICE);

echo "<div class='alert alert-success'>";
echo "ErrorContextToolkit 提供了完整的错误上下文收集功能";
echo "</div>";

总结

虽然PHP没有内置get_error_context()函数,但我们可以创建自定义函数来收集错误发生时的上下文信息。以下是关键要点:

  • 自定义实现:可以通过debug_backtrace()get_defined_vars()等函数实现上下文收集
  • 多层次信息:包括调用栈、变量状态、环境信息、请求数据等
  • 安全考虑:在生产环境中需要过滤敏感信息,保护用户数据
  • 性能优化:根据需要收集不同级别的信息,避免性能问题
  • 实用工具:可以创建调试工具、错误处理器、异常处理器等
  • 格式支持:支持JSON、HTML、YAML等多种输出格式

最佳实践:

  1. 在开发环境中收集详细上下文,便于调试
  2. 在生产环境中过滤敏感信息,保护隐私
  3. 根据错误级别决定收集信息的详细程度
  4. 使用结构化格式(如JSON)记录日志,便于分析
  5. 考虑性能影响,避免在关键路径中收集过多信息