Logging: Enable viewing log entry context data in the DB logger list table (#41936)

This commit is contained in:
Leif Singer 2023-12-07 22:58:05 +01:00 committed by GitHub
commit 7838adc1b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 166 additions and 14 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Enable viewing context data in the database logger list table

View File

@ -1561,6 +1561,26 @@ table.wc_status_table--tools {
.column-source {
width: 15%;
}
.column-context {
width: 10%;
}
}
.column-context {
.button {
span {
line-height: 1.3;
}
}
}
.log-context {
display: none;
pre {
white-space: pre-wrap;
}
}
}

View File

@ -54,4 +54,37 @@ abstract class WC_Log_Handler implements WC_Log_Handler_Interface {
)
);
}
/**
* Get a backtrace that shows where the logging function was called.
*
* @return array
*/
protected static function get_backtrace() {
// Get the filenames of the logging-related classes so we can ignore them.
$ignore_files = array_map(
function( $class ) {
try {
$reflector = new \ReflectionClass( $class );
return $reflector->getFileName();
} catch ( Exception $exception ) {
return null;
}
},
array( wc_get_logger(), self::class, static::class )
);
$backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
$filtered_backtrace = array_filter(
$backtrace,
function( $frame ) use ( $ignore_files ) {
$ignore = isset( $frame['file'] ) && in_array( $frame['file'], $ignore_files, true );
return ! $ignore;
}
);
return array_values( $filtered_backtrace );
}
}

View File

@ -92,6 +92,40 @@ class WC_Admin_Log_Table_List extends WP_List_Table {
<?php
}
/**
* Generates the table rows.
*
* @return void
*/
public function display_rows() {
foreach ( $this->items as $log ) {
$this->single_row( $log );
if ( ! empty( $log['context'] ) ) {
$this->context_row( $log );
}
}
}
/**
* Render the additional table row that contains extra log context data.
*
* @param array $log Log entry data.
*
* @return void
*/
protected function context_row( $log ) {
// Maintains alternating row background colors.
?>
<tr style="display: none"><td></td></tr>
<tr id="log-context-<?php echo esc_attr( $log['log_id'] ); ?>" class="log-context">
<td colspan="<?php echo esc_attr( $this->get_column_count() ); ?>">
<p><strong><?php esc_html_e( 'Additional context', 'woocommerce' ); ?></strong></p>
<pre><?php echo esc_html( $log['context'] ); ?></pre>
</td>
</tr>
<?php
}
/**
* Get list columns.
*
@ -104,6 +138,7 @@ class WC_Admin_Log_Table_List extends WP_List_Table {
'level' => __( 'Level', 'woocommerce' ),
'message' => __( 'Message', 'woocommerce' ),
'source' => __( 'Source', 'woocommerce' ),
'context' => __( 'Context', 'woocommerce' ),
);
}
@ -180,6 +215,36 @@ class WC_Admin_Log_Table_List extends WP_List_Table {
return esc_html( $log['source'] );
}
/**
* Context column.
*
* @param array $log Log entry data.
*
* @return string
*/
public function column_context( $log ) {
$content = '';
if ( ! empty( $log['context'] ) ) {
ob_start();
?>
<button
class="log-toggle button button-secondary button-small"
data-log-id="<?php echo esc_attr( $log['log_id'] ); ?>"
data-toggle-status="off"
data-label-show="<?php esc_attr_e( 'Show context', 'woocommerce' ); ?>"
data-label-hide="<?php esc_attr_e( 'Hide context', 'woocommerce' ); ?>"
>
<span class="dashicons dashicons-arrow-down-alt2"></span>
<span class="log-toggle-label screen-reader-text"><?php esc_html_e( 'Show context', 'woocommerce' ); ?></span>
</button>
<?php
$content = ob_get_clean();
}
return $content;
}
/**
* Get bulk actions.
*
@ -273,7 +338,7 @@ class WC_Admin_Log_Table_List extends WP_List_Table {
$offset = $this->get_items_query_offset();
$query_items = "
SELECT log_id, timestamp, level, message, source
SELECT log_id, timestamp, level, message, source, context
FROM {$wpdb->prefix}woocommerce_log
{$where} {$order} {$limit} {$offset}
";

View File

@ -20,6 +20,35 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php submit_button( __( 'Flush all logs', 'woocommerce' ), 'delete', 'flush-logs' ); ?>
<?php wp_nonce_field( 'woocommerce-status-logs' ); ?>
</form>
<script>
document.addEventListener( 'DOMContentLoaded', function() {
var contextToggles = Array.from( document.getElementsByClassName( 'log-toggle' ) );
contextToggles.forEach( ( element ) => {
element.addEventListener( 'click', ( event ) => {
event.preventDefault();
const button = event.currentTarget;
const buttonLabel = button.querySelector( '.log-toggle-label' );
const buttonIcon = button.querySelector( '.dashicons' );
const context = document.getElementById( 'log-context-' + button.dataset.logId );
switch ( button.dataset.toggleStatus ) {
case 'off':
context.style.display = 'table-row';
buttonLabel.textContent = button.dataset.labelHide;
buttonIcon.classList.replace( 'dashicons-arrow-down-alt2', 'dashicons-arrow-up-alt2' );
button.dataset.toggleStatus = 'on';
break;
case 'on':
context.style.display = 'none';
buttonLabel.textContent = button.dataset.labelShow;
buttonIcon.classList.replace( 'dashicons-arrow-up-alt2', 'dashicons-arrow-down-alt2' );
button.dataset.toggleStatus = 'off';
break;
}
} );
} );
} );
</script>
<?php
wc_enqueue_js(
"jQuery( '#flush-logs' ).on( 'click', function() {

View File

@ -77,12 +77,13 @@ class WC_Log_Handler_DB extends WC_Log_Handler {
'%s', // possible serialized context.
);
unset( $context['source'] );
if ( ! empty( $context ) ) {
try {
$insert['context'] = serialize( $context ); // @codingStandardsIgnoreLine.
} catch ( Exception $e ) {
$insert['context'] = serialize( 'There was an error while serializing the context: ' . $e->getMessage() );
if ( isset( $context['backtrace'] ) && true === filter_var( $context['backtrace'], FILTER_VALIDATE_BOOLEAN ) ) {
$context['backtrace'] = self::get_backtrace();
}
$insert['context'] = wp_json_encode( $context, JSON_PRETTY_PRINT );
}
return false !== $wpdb->insert( "{$wpdb->prefix}woocommerce_log", $insert, $format );

View File

@ -49,63 +49,63 @@ class WC_Tests_Log_Handler_DB extends WC_Unit_Test_Case {
'level' => WC_Log_Levels::get_level_severity( 'debug' ),
'message' => 'msg_debug',
'source' => 'source_debug',
'context' => serialize( array( 'source' => 'source_debug' ) ),
'context' => '',
),
array(
'timestamp' => $expected_ts,
'level' => WC_Log_Levels::get_level_severity( 'info' ),
'message' => 'msg_info',
'source' => 'source_info',
'context' => serialize( array( 'source' => 'source_info' ) ),
'context' => '',
),
array(
'timestamp' => $expected_ts,
'level' => WC_Log_Levels::get_level_severity( 'notice' ),
'message' => 'msg_notice',
'source' => 'source_notice',
'context' => serialize( array( 'source' => 'source_notice' ) ),
'context' => '',
),
array(
'timestamp' => $expected_ts,
'level' => WC_Log_Levels::get_level_severity( 'warning' ),
'message' => 'msg_warning',
'source' => 'source_warning',
'context' => serialize( array( 'source' => 'source_warning' ) ),
'context' => '',
),
array(
'timestamp' => $expected_ts,
'level' => WC_Log_Levels::get_level_severity( 'error' ),
'message' => 'msg_error',
'source' => 'source_error',
'context' => serialize( array( 'source' => 'source_error' ) ),
'context' => '',
),
array(
'timestamp' => $expected_ts,
'level' => WC_Log_Levels::get_level_severity( 'critical' ),
'message' => 'msg_critical',
'source' => 'source_critical',
'context' => serialize( array( 'source' => 'source_critical' ) ),
'context' => '',
),
array(
'timestamp' => $expected_ts,
'level' => WC_Log_Levels::get_level_severity( 'alert' ),
'message' => 'msg_alert',
'source' => 'source_alert',
'context' => serialize( array( 'source' => 'source_alert' ) ),
'context' => '',
),
array(
'timestamp' => $expected_ts,
'level' => WC_Log_Levels::get_level_severity( 'emergency' ),
'message' => 'msg_emergency',
'source' => 'source_emergency',
'context' => serialize( array( 'source' => 'source_emergency' ) ),
'context' => '',
),
array(
'timestamp' => $expected_ts,
'level' => WC_Log_Levels::get_level_severity( 'debug' ),
'message' => 'context_test',
'source' => pathinfo( __FILE__, PATHINFO_FILENAME ),
'context' => serialize( $context ),
'context' => wp_json_encode( $context, JSON_PRETTY_PRINT ),
),
);