brianhenryie/bh-wp-logger

WordPress 插件的 PSR 日志记录器,拥有友好的 WP_List_Table 用户界面。

This package is auto-updated.

Last update: 2024-09-08 23:41:04 UTC


README

PHPUnit PHP 7.4

BH WP Logger

WordPress 插件的零配置日志记录器用户界面。

$logger = Logger::instance();

封装现有的 PSR-3 日志记录器并添加一些用户界面。

默认使用 KLogger,指定时使用 WC_Logger,当日志级别设置为 "none" 时使用 NullLogger。

使用 PHP 的 set_error_handler() 捕获 PHP 弃用/warning/notice/错误。

钩入 WordPress 的弃用函数钩子(例如 deprecated_function_run 等),只记录每天一次。

使用 PHP 的 register_shutdown_function() 捕获与插件相关的异常。

在 cron 中删除 30 天前的日志文件。

在错误时记录完整的堆栈跟踪。当级别为调试时,在每次日志中记录两个步骤的堆栈跟踪。

用户界面

WP_List_Table 中显示日志。

Logs WP_List_Table

每次有新错误时,显示可关闭的管理员错误通知。

Admin Error Notice

在 plugins.php 中的插件条目上添加日志查看链接。

Plugins page logs link

当日志消息包含 `wp_user:123`(注意:由单引号包围)时,它将被替换为用户资料的链接。这允许在不记录 PII 的情况下记录对用户的引用。

类似地,任何帖子类型都可以通过 `post_type_name:123`(例如 `shop_order:123` 将链接到 WooCommerce 订单)链接。

Links in log message

使用

Composer

composer require brianhenryie/bh-wp-logger

直到 v1.0.0 版本,每次发布都可能有破坏性的变化。

实例化

您应该使用 brianhenryie/strauss 来前缀库的命名空间。然后 Strauss 的自动加载器会为您包括文件。

以下将生效,但提供设置会更快、更可靠

$logger = Logger::instance();

提供设置

$logger_settings = new class() implements BrianHenryIE\WP_Logger\API\Logger_Settings_Interface {
    use BrianHenryIE\WP_Logger\Logger_Settings_Trait;
    
	public function get_log_level(): string {
		return LogLevel::INFO;
	}

	// This is used in admin notices.
	public function get_plugin_name(): string {
		return "My Plugin Name";
	}

	// This is used in option names and URLs.
	public function get_plugin_slug(): string {
		return "my-plugin-name";
	}

	// This is needed for the plugins.php logs link.
	public function get_plugin_basename(): string {
		return "my-plugin-name/my-plugin-name.php";
	}
};
$logger = Logger::instance( $logger_settings );

然后传递您的 $logger 实例。

一旦实例化了日志记录器,后续对 ::instance() 的调用将返回现有实例,并且忽略任何传递的 $logger_settings

要使用 WooCommerce 的原生 WC_Logger,在设置对象上使用 WooCommerce_Logger_Interface 接口(它仅扩展 Logger_Settings_Interface)。

$logger_settings = new class() implements BrianHenryIE\WP_Logger\WooCommerce\WooCommerce_Logger_Settings_Interface {
    ...

WooCommerce 设置

以下内容可以用于 WooCommerce 设置 API。

$log_levels        = array( 'none', LogLevel::ERROR, LogLevel::WARNING, LogLevel::NOTICE, LogLevel::INFO, LogLevel::DEBUG );
$log_levels_option = array();
foreach ( $log_levels as $log_level ) {
    $log_levels_option[ $log_level ] = ucfirst( $log_level );
}

$setting_fields[] = array(
    'title'    => __( 'Log Level', 'text-domain' ),
    'label'    => __( 'Enable Logging', 'text-domain' ),
    'type'     => 'select',
    'options'  => $log_levels_option,
    'desc'    => __( 'Increasingly detailed levels of logs. ', 'text-domain' ) . '<a href="' . admin_url( 'admin.php?page=plugin-slug-logs' ) . '">View Logs</a>',
    'desc_tip' => false,
    'default'  => 'notice',
    'id'       => 'text-domain-log-level',
);

WooCommerce Settings

过滤器

有两个过滤器,用于在保存日志数据时修改日志数据,以及在呈现日志数据时修改日志数据。

例如,更改特定日志消息的日志级别

/**
 * Modify the log data array or return null to cancel logging this entry.
 * The library php-http/logger-plugin is using INFO for detailed logging, let's change that to DEBUG.
 *
 * @hooked {$plugin_slug}_bh_wp_logger_log
 * 
 * @pararm array{level:string,message:string,context:array} $log_data
 * @param Logger_Settings_Interface $settings
 * @param BH_WP_PSR_Logger $bh_wp_psr_logger
 */
function modify_log_data( array $log_data, \BrianHenryIE\WP_Logger\Logger_Settings_Interface $settings, \BrianHenryIE\WP_Logger\API\BH_WP_PSR_Logger $bh_wp_psr_logger): ?array {
    
    if ( 0 === strpos( $log_data['message'], 'Sending request' ) ) {
        $log_data['level'] = LogLevel::DEBUG;
    }

    return $log_data;
}
add_filter( "{$plugin_slug}_bh_wp_logger_log", 'modify_log_data', 10, 3 );

例如,在日志表显示时将日志中的文本转换为超链接

/**
 * Update ` `wc_order:123` ` with links to the order.
 * Use preg_replace_callback to find and replace all instances in the string.
 *
 * @hooked {$plugin_slug}_bh_wp_logger_column
 *
 * @param string                                                          $column_output The column output so far.
 * @param array{time:string, level:string, message:string, context:array} $item The log entry row.
 * @param string                                                          $column_name The current column name.
 * @param Logger_Settings_Interface                                       $logger_settings The logger settings.
 * @param BH_WP_PSR_Logger                                                $bh_wp_psr_logger The logger API instance.
 *
 * @return string
 */
function replace_wc_order_id_with_link( string $column_output, array $item, string $column_name,\BrianHenryIE\WP_Logger\Logger_Settings_Interface $logger_settings, \BrianHenryIE\WP_Logger\API\BH_WP_PSR_Logger $bh_wp_psr_logger ): string {

    if ( 'message' !== $column_name ) {
        return $column_output;
    }

    $callback = function( array $matches ): string {

        $url  = admin_url( "post.php?post={$matches[1]}&action=edit" );
        $link = "<a href=\"{$url}\">Order {$matches[1]}</a>";

        return $link;
    };

    $message = preg_replace_callback( '/`wc_order:(\d+)`/', $callback, $column_output ) ?? $column_output;

    return $message;
}
add_filter( "{$plugin_slug}_bh_wp_logger_column", 'replace_wc_order_id_with_link', 10, 5 );

WP_Mock

如果您使用 WP_Mock 进行测试,并且您正在实例化此日志记录器,以下内容可能会有所帮助

\Patchwork\redefine(
    array( Logger::class, '__construct' ),
    function( $settings ) {}
);

测试插件

test-plugin 文件夹包含一个小的插件,其中包含按钮来触发可以记录的错误类型。

Test Plugin

最佳实践

根据我有限的日志记录经验,我在函数开始时添加一个 debug 日志,并在函数返回时添加适当的 info...error

TODO

  • 检查日志目录不是公开可访问的
  • 检查上传目录的 chmod(可写)。=> 查看 brianhenryie/bh-wp-private-uploads
  • 将当前用户添加到上下文
  • 不要记录空上下文(WC)
  • 显示管理员通知的错误的级别选项
  • 显示管理员通知的用户能力选项(过滤器,至少)
  • 零配置 WC_Logger:检测插件名称中的 "wc"、"woo"。
  • 在上下文 json 中使用 代码美化工具 : 已使用 caldwell/renderjson
  • 分页和过滤
  • 消息中的超链接
  • 记录上次查看日志的时间戳,如果有新的日志,将 plugins.php 链接加粗。
  • 自动删除旧日志
  • 当访问日志页面时,日志通知应消失
  • 删除敏感数据。例如,在保存的日志中使用 userid:123,并在显示时用更丰富的数据替换它
  • 将错误添加到仪表板站点健康小部件
  • 确保输出被正确转义

一些小问题

  • 调试日志可能可以移动到关闭处理程序
  • 用于抑制重复日志的转瞬即逝可能不够高效

状态

到目前为止,我认为它主要是由我使用的,即内部项目。没有严重问题。它应该对每个人都适用,但我希望从其他人那里得到一些反馈,看看它对你来说效果如何。

一旦我追上了 WPCS、PhpStan 和 PhpUnit,我就会从 Semver 1.0.0 开始。大约有 65 个测试和 43% 的覆盖率。WPCS + PHPStan 都相当不错。

我认为这比大多数 WordPress 插件的代码质量都要高。