Merge pull request #17755 from woocommerce/feature/webhook-delivery-logging
Webhook Logging via WC_Logger
This commit is contained in:
commit
34b7f67646
|
@ -297,32 +297,11 @@ class WC_Admin_Webhooks {
|
|||
/**
|
||||
* Logs output.
|
||||
*
|
||||
* @param WC_Webhook $webhook Webhook instance.
|
||||
* @deprecated 3.3.0
|
||||
* @param WC_Webhook $webhook Deprecated.
|
||||
*/
|
||||
public static function logs_output( $webhook ) {
|
||||
$current = isset( $_GET['log_page'] ) ? absint( $_GET['log_page'] ) : 1; // WPCS: input var okay, CSRF ok.
|
||||
$args = array(
|
||||
'post_id' => $webhook->get_id(),
|
||||
'status' => 'approve',
|
||||
'type' => 'webhook_delivery',
|
||||
'number' => 10,
|
||||
);
|
||||
|
||||
if ( 1 < $current ) {
|
||||
$args['offset'] = ( $current - 1 ) * 10;
|
||||
}
|
||||
|
||||
remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_webhook_comments' ), 10, 1 );
|
||||
|
||||
$logs = get_comments( $args );
|
||||
|
||||
add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_webhook_comments' ), 10, 1 );
|
||||
|
||||
if ( $logs ) {
|
||||
include_once( dirname( __FILE__ ) . '/settings/views/html-webhook-logs.php' );
|
||||
} else {
|
||||
echo '<p>' . esc_html__( 'This Webhook has no log yet.', 'woocommerce' ) . '</p>';
|
||||
}
|
||||
public static function logs_output( $webhook = 'deprecated' ) {
|
||||
wc_deprecated_function( 'WC_Admin_Webhooks::logs_output', '3.3' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -357,48 +336,12 @@ class WC_Admin_Webhooks {
|
|||
/**
|
||||
* Get the logs navigation.
|
||||
*
|
||||
* @param int $total Number of logs.
|
||||
* @param WC_Webhook $webhook Webhook instance.
|
||||
*
|
||||
* @return string
|
||||
* @deprecated 3.3.0
|
||||
* @param int $total Deprecated.
|
||||
* @param WC_Webhook $webhook Deprecated.
|
||||
*/
|
||||
public static function get_logs_navigation( $total, $webhook ) {
|
||||
$pages = ceil( $total / 10 );
|
||||
$current = isset( $_GET['log_page'] ) ? absint( $_GET['log_page'] ) : 1; // WPCS: input var okay, CSRF ok.
|
||||
|
||||
$html = '<div class="webhook-logs-navigation">';
|
||||
|
||||
$html .= '<p class="info" style="float: left;"><strong>';
|
||||
|
||||
$html .= sprintf(
|
||||
/* translators: 1: items count (i.e. 8 items) 2: current page 3: total pages */
|
||||
esc_html__( '%1$s – Page %2$d of %3$d', 'woocommerce' ),
|
||||
/* translators: %d: items count */
|
||||
esc_html( sprintf( _n( '%d item', '%d items', $total, 'woocommerce' ), $total ) ),
|
||||
$current,
|
||||
$pages
|
||||
);
|
||||
$html .= '</strong></p>';
|
||||
|
||||
if ( 1 < $pages ) {
|
||||
$html .= '<p class="tools" style="float: right;">';
|
||||
if ( 1 === $current ) {
|
||||
$html .= '<button class="button-primary" disabled="disabled">' . __( '‹ Previous', 'woocommerce' ) . '</button> ';
|
||||
} else {
|
||||
$html .= '<a class="button-primary" href="' . admin_url( 'admin.php?page=wc-settings&tab=api§ion=webhooks&edit-webhook=' . $webhook->get_id() . '&log_page=' . ( $current - 1 ) ) . '#webhook-logs">' . __( '‹ Previous', 'woocommerce' ) . '</a> ';
|
||||
}
|
||||
|
||||
if ( $pages === $current ) {
|
||||
$html .= '<button class="button-primary" disabled="disabled">' . __( 'Next ›', 'woocommerce' ) . '</button>';
|
||||
} else {
|
||||
$html .= '<a class="button-primary" href="' . admin_url( 'admin.php?page=wc-settings&tab=api§ion=webhooks&edit-webhook=' . $webhook->get_id() . '&log_page=' . ( $current + 1 ) ) . '#webhook-logs">' . __( 'Next ›', 'woocommerce' ) . '</a>';
|
||||
}
|
||||
$html .= '</p>';
|
||||
}
|
||||
|
||||
$html .= '<div class="clear"></div></div>';
|
||||
|
||||
return $html;
|
||||
wc_deprecated_function( 'WC_Admin_Webhooks::get_logs_navigation', '3.3' );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td><?php echo date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $log['comment']->comment_date_gmt ), true ); ?></td>
|
||||
<td><?php echo esc_attr( $log['request_url'] ); ?></td>
|
||||
<td>
|
||||
<p><strong><?php _e( 'Method', 'woocommerce' ); ?>: </strong><?php echo esc_html( $log['request_method'] ); ?></p>
|
||||
<p><strong><?php _e( 'Duration', 'woocommerce' ); ?>: </strong><?php echo esc_html( $log['duration'] ); ?></p>
|
||||
<p><strong><?php _e( 'Headers', 'woocommerce' ); ?>:</strong></p>
|
||||
<ul>
|
||||
<?php foreach ( (array) $log['request_headers'] as $key => $value ) : ?>
|
||||
<li><strong><em><?php echo strtolower( esc_html( $key ) ); ?>: </em></strong><code><?php echo esc_html( $value ); ?></code></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<p><strong><?php _e( 'Content', 'woocommerce' ); ?>: </strong></p>
|
||||
<pre><code><?php echo esc_html( $log['request_body'] ); ?></code></pre>
|
||||
</td>
|
||||
<td>
|
||||
<p><strong><?php _e( 'Status', 'woocommerce' ); ?>: </strong><?php echo esc_html( $log['summary'] ); ?></p>
|
||||
<p><strong><?php _e( 'Headers', 'woocommerce' ); ?>:</strong></p>
|
||||
<ul>
|
||||
<?php $response_headers = is_callable( array( $log['response_headers'], 'getAll' ) ) ? $log['response_headers']->getAll() : $log['response_headers']; ?>
|
||||
<?php foreach ( (array) $response_headers as $key => $value ) : ?>
|
||||
<li><strong><em><?php echo strtolower( esc_html( $key ) ); ?>: </em></strong><code><?php echo esc_html( $value ); ?></code></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<?php if ( ! empty( $log['response_body'] ) ) : ?>
|
||||
<h4><?php _e( 'Content', 'woocommerce' ); ?>:</h4>
|
||||
<p><?php echo esc_html( $log['response_body'] ); ?></p>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$count_comments = wp_count_comments( $webhook->id );
|
||||
$total = $count_comments->approved;
|
||||
|
||||
?>
|
||||
|
||||
<?php echo WC_Admin_Webhooks::get_logs_navigation( $total, $webhook ); ?>
|
||||
|
||||
<table id="webhook-logs-table" class="widefat">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e( 'Date', 'woocommerce' ); ?></th>
|
||||
<th><?php _e( 'URL', 'woocommerce' ); ?></th>
|
||||
<th><?php _e( 'Request', 'woocommerce' ); ?></th>
|
||||
<th><?php _e( 'Response', 'woocommerce' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th><?php _e( 'Date', 'woocommerce' ); ?></th>
|
||||
<th><?php _e( 'URL', 'woocommerce' ); ?></th>
|
||||
<th><?php _e( 'Request', 'woocommerce' ); ?></th>
|
||||
<th><?php _e( 'Response', 'woocommerce' ); ?></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ( $logs as $log ) {
|
||||
$log = $webhook->get_delivery_log( $log->comment_ID );
|
||||
|
||||
include( 'html-webhook-log.php' );
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php echo WC_Admin_Webhooks::get_logs_navigation( $total, $webhook ); ?>
|
|
@ -686,6 +686,7 @@ CREATE TABLE {$wpdb->prefix}wc_webhooks (
|
|||
pending_delivery tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (webhook_id),
|
||||
KEY user_id (user_id)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_download_log (
|
||||
download_log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
timestamp datetime NOT NULL,
|
||||
|
|
|
@ -300,7 +300,7 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
|||
case 'product':
|
||||
$class = 'WC_REST_' . ucfirst( $resource ) . 's' . $version_suffix . '_Controller';
|
||||
$request = new WP_REST_Request( 'GET' );
|
||||
$controller = new $class;
|
||||
$controller = new $class();
|
||||
|
||||
// Bulk and quick edit action hooks return a product object instead of an ID.
|
||||
if ( 'product' === $resource && 'updated' === $event && is_a( $resource_id, 'WC_Product' ) ) {
|
||||
|
@ -380,47 +380,65 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a new comment for log the delivery request/response and.
|
||||
* return the ID for inclusion in the webhook request.
|
||||
* Generate a new unique hash as a delivery id based on current time and wehbook id.
|
||||
* Return the hash for inclusion in the webhook request.
|
||||
*
|
||||
* @todo Update to use log system.
|
||||
* @since 2.2.0
|
||||
* @return int
|
||||
* @return string
|
||||
*/
|
||||
public function get_new_delivery_id() {
|
||||
|
||||
$comment_data = apply_filters( 'woocommerce_new_webhook_delivery_data', array(
|
||||
'comment_author' => __( 'WooCommerce', 'woocommerce' ),
|
||||
'comment_author_email' => sanitize_email( sprintf( '%s@%s', strtolower( __( 'WooCommerce', 'woocommerce' ) ), isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ) : 'noreply.com' ) ),
|
||||
'comment_post_ID' => $this->get_id(),
|
||||
'comment_agent' => 'WooCommerce Hookshot',
|
||||
'comment_type' => 'webhook_delivery',
|
||||
'comment_parent' => 0,
|
||||
'comment_approved' => 1,
|
||||
), $this->get_id() );
|
||||
|
||||
$comment_id = wp_insert_comment( $comment_data );
|
||||
|
||||
return $comment_id;
|
||||
// Since we no longer use comments to store delivery logs, we generate a unique hash instead based on current time and webhook ID.
|
||||
return wp_hash( $this->get_id() . strtotime( 'now' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the delivery request/response.
|
||||
*
|
||||
* @todo Update to use log system.
|
||||
* @since 2.2.0
|
||||
* @param int $delivery_id Previously created comment ID.
|
||||
* @param string $delivery_id Previously created hash.
|
||||
* @param array $request Request data.
|
||||
* @param array|WP_Error $response Response data.
|
||||
* @param float $duration Request duration.
|
||||
*/
|
||||
public function log_delivery( $delivery_id, $request, $response, $duration ) {
|
||||
// Save request data.
|
||||
add_comment_meta( $delivery_id, '_request_method', $request['method'] );
|
||||
add_comment_meta( $delivery_id, '_request_headers', array_merge( array(
|
||||
$logger = wc_get_logger();
|
||||
$message = array(
|
||||
'Webhook Delivery' => array(
|
||||
'Delivery ID' => $delivery_id,
|
||||
'Date' => date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( 'now' ), true ),
|
||||
'URL' => $this->get_delivery_url(),
|
||||
'Duration' => $duration,
|
||||
'Request' => array(
|
||||
'Method' => $request['method'],
|
||||
'Headers' => array_merge(
|
||||
array(
|
||||
'User-Agent' => $request['user-agent'],
|
||||
), $request['headers'] ) );
|
||||
add_comment_meta( $delivery_id, '_request_body', wp_slash( $request['body'] ) );
|
||||
),
|
||||
$request['headers']
|
||||
),
|
||||
),
|
||||
'Body' => wp_slash( $request['body'] ),
|
||||
),
|
||||
);
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$message['Webhook Delivery']['Response'] = array(
|
||||
'Code' => $response->get_error_code(),
|
||||
'Message' => $response->get_error_message(),
|
||||
'Headers' => array(),
|
||||
'Body' => '',
|
||||
);
|
||||
} else {
|
||||
$message['Webhook Delivery']['Response'] = array(
|
||||
'Code' => wp_remote_retrieve_response_code( $response ),
|
||||
'Message' => wp_remote_retrieve_response_message( $response ),
|
||||
'Headers' => wp_remote_retrieve_headers( $response ),
|
||||
'Body' => wp_remote_retrieve_body( $response ),
|
||||
);
|
||||
}
|
||||
|
||||
$logger->info( wc_print_r( $message, true ), array(
|
||||
'source' => 'webhooks-delivery',
|
||||
) );
|
||||
|
||||
// Parse response.
|
||||
if ( is_wp_error( $response ) ) {
|
||||
|
@ -436,22 +454,9 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
|||
$response_body = wp_remote_retrieve_body( $response );
|
||||
}
|
||||
|
||||
// Save response data.
|
||||
add_comment_meta( $delivery_id, '_response_code', $response_code );
|
||||
add_comment_meta( $delivery_id, '_response_message', $response_message );
|
||||
add_comment_meta( $delivery_id, '_response_headers', $response_headers );
|
||||
add_comment_meta( $delivery_id, '_response_body', $response_body );
|
||||
|
||||
// Save duration.
|
||||
add_comment_meta( $delivery_id, '_duration', $duration );
|
||||
|
||||
// Set a summary for quick display.
|
||||
$args = array(
|
||||
'comment_ID' => $delivery_id,
|
||||
'comment_content' => sprintf( 'HTTP %s %s: %s', $response_code, $response_message, $response_body ),
|
||||
);
|
||||
|
||||
wp_update_comment( $args );
|
||||
$logger->info( wc_print_r( $message, true ), array(
|
||||
'source' => 'webhooks-delivery',
|
||||
) );
|
||||
|
||||
// Track failures.
|
||||
if ( intval( $response_code ) >= 200 && intval( $response_code ) < 300 ) {
|
||||
|
@ -459,18 +464,6 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
|||
} else {
|
||||
$this->failed_delivery();
|
||||
}
|
||||
|
||||
// Keep the 25 most recent delivery logs.
|
||||
$log = wp_count_comments( $this->get_id() );
|
||||
if ( $log->total_comments > apply_filters( 'woocommerce_max_webhook_delivery_logs', 25 ) ) {
|
||||
global $wpdb;
|
||||
|
||||
$comment_id = $wpdb->get_var( $wpdb->prepare( "SELECT comment_ID FROM {$wpdb->comments} WHERE comment_post_ID = %d ORDER BY comment_date_gmt ASC LIMIT 1", $this->get_id() ) );
|
||||
|
||||
if ( $comment_id ) {
|
||||
wp_delete_comment( $comment_id, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -493,31 +486,11 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
|||
/**
|
||||
* Get the delivery logs for this webhook.
|
||||
*
|
||||
* @todo Update to use log system.
|
||||
* @since 2.2.0
|
||||
* @return array
|
||||
*/
|
||||
public function get_delivery_logs() {
|
||||
$args = array(
|
||||
'post_id' => $this->get_id(),
|
||||
'status' => 'approve',
|
||||
'type' => 'webhook_delivery',
|
||||
);
|
||||
|
||||
remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_webhook_comments' ), 10, 1 );
|
||||
|
||||
$logs = get_comments( $args );
|
||||
|
||||
add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_webhook_comments' ), 10, 1 );
|
||||
|
||||
$delivery_logs = array();
|
||||
|
||||
foreach ( $logs as $log ) {
|
||||
$log = $this->get_delivery_log( $log->comment_ID );
|
||||
$delivery_logs[] = ( ! empty( $log ) ? $log : array() );
|
||||
}
|
||||
|
||||
return $delivery_logs;
|
||||
return esc_url( add_query_arg( 'log_file', wc_get_log_file_name( 'webhooks-delivery' ), admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -529,35 +502,13 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
|||
* + request headers/body
|
||||
* + response code/message/headers/body
|
||||
*
|
||||
* @todo Update to use log system.
|
||||
* @since 2.2
|
||||
* @deprecated 3.3.0
|
||||
* @param int $delivery_id Delivery ID.
|
||||
* @return bool|array false if invalid delivery ID, array of log data otherwise
|
||||
* @return void
|
||||
*/
|
||||
public function get_delivery_log( $delivery_id ) {
|
||||
$log = get_comment( $delivery_id );
|
||||
|
||||
// Valid comment and ensure delivery log belongs to this webhook.
|
||||
if ( is_null( $log ) || $log->comment_post_ID !== $this->get_id() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$delivery_log = array(
|
||||
'id' => intval( $delivery_id ),
|
||||
'duration' => get_comment_meta( $delivery_id, '_duration', true ),
|
||||
'summary' => $log->comment_content,
|
||||
'request_method' => get_comment_meta( $delivery_id, '_request_method', true ),
|
||||
'request_url' => $this->get_delivery_url(),
|
||||
'request_headers' => get_comment_meta( $delivery_id, '_request_headers', true ),
|
||||
'request_body' => get_comment_meta( $delivery_id, '_request_body', true ),
|
||||
'response_code' => get_comment_meta( $delivery_id, '_response_code', true ),
|
||||
'response_message' => get_comment_meta( $delivery_id, '_response_message', true ),
|
||||
'response_headers' => get_comment_meta( $delivery_id, '_response_headers', true ),
|
||||
'response_body' => get_comment_meta( $delivery_id, '_response_body', true ),
|
||||
'comment' => $log,
|
||||
);
|
||||
|
||||
return apply_filters( 'woocommerce_webhook_delivery_log', $delivery_log, $delivery_id, $this->get_id() );
|
||||
wc_deprecated_function( 'WC_Webhook::get_delivery_log', '3.3' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -340,13 +340,29 @@ class WC_Log_Handler_File extends WC_Log_Handler {
|
|||
*/
|
||||
public static function get_log_file_path( $handle ) {
|
||||
if ( function_exists( 'wp_hash' ) ) {
|
||||
return trailingslashit( WC_LOG_DIR ) . sanitize_file_name( $handle . '-' . wp_hash( $handle ) . '.log' );
|
||||
return trailingslashit( WC_LOG_DIR ) . self::get_log_file_name( $handle );
|
||||
} else {
|
||||
wc_doing_it_wrong( __METHOD__, __( 'This method should not be called before plugins_loaded.', 'woocommerce' ), '3.0' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log file name.
|
||||
*
|
||||
* @since 3.3
|
||||
* @param string $handle Log name.
|
||||
* @return bool|string The log file name or false if cannot be determined.
|
||||
*/
|
||||
public static function get_log_file_name( $handle ) {
|
||||
if ( function_exists( 'wp_hash' ) ) {
|
||||
return sanitize_file_name( $handle . '-' . wp_hash( $handle ) . '.log' );
|
||||
} else {
|
||||
wc_doing_it_wrong( __METHOD__, __( 'This method should not be called before plugins_loaded.', 'woocommerce' ), '3.3' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache log to write later.
|
||||
*
|
||||
|
|
|
@ -811,6 +811,18 @@ function wc_get_log_file_path( $handle ) {
|
|||
return WC_Log_Handler_File::get_log_file_path( $handle );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log file name.
|
||||
*
|
||||
* @since 3.3
|
||||
*
|
||||
* @param string $handle Name.
|
||||
* @return string The log file name.
|
||||
*/
|
||||
function wc_get_log_file_name( $handle ) {
|
||||
return WC_Log_Handler_File::get_log_file_name( $handle );
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively get page children.
|
||||
* @param int $page_id
|
||||
|
|
Loading…
Reference in New Issue