Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
WPCOMSH_Log
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 6
132
0.00% covered (danger)
0.00%
0 / 1
 init
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 unsafe_direct_log
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 add_hooks
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 log
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 send_to_api
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * WPCOMSH Log file.
4 *
5 * @package wpcomsh
6 */
7
8/**
9 * Class WPCOMSH_Log
10 *
11 * This is an interface for logging arbitrary data to wpcom logstash cluster.
12 * This auto-initializes and provides a hook to log data:
13 * ```
14 * do_action( 'wpcomsh_log', "test" );
15 * ```
16 *
17 * You can see logs in Kibana, log2logstash index, `feature:automated_transfer`.
18 *
19 * Note that logging must be enabled for the site for the logs to be sent,
20 * which involves enabling the `at_options_logging_on` site option on the
21 * Jetpack site.
22 */
23class WPCOMSH_Log {
24    /**
25     * Logging Endpoint URL.
26     *
27     * @var string
28     */
29    protected static $log_endpoint = 'https://public-api.wordpress.com/rest/v1.1/automated-transfers/log';
30
31    /**
32     * Class instance.
33     *
34     * @var WPCOMSH_Log
35     */
36    private static $instance;
37
38    /**
39     * Queue of log messages.
40     *
41     * @var array
42     */
43    private $log_queue = array();
44
45    /**
46     * Whether it has a shutdown hook.
47     *
48     * @var bool
49     */
50    private $has_shutdown_hook = false;
51
52    /**
53     * Site URL.
54     *
55     * @var string
56     */
57    private $siteurl;
58
59    /**
60     * This instantiates the logging system. Because constructor is private, it can be only set up with `init` or `unsafe_direct_log`.
61     * `init` respects `at_options_logging_on` option. This essentially turns logging on/off so that we don't flood
62     * endpoint with too many requests.
63     * This is to be hooked into wp `init` hook.
64     */
65    public static function init() {
66        if ( ! get_option( 'at_options_logging_on' ) ) {
67            return;
68        }
69
70        if ( self::$instance ) {
71            return;
72        }
73
74        self::$instance = new self();
75        self::$instance->add_hooks();
76    }
77
78    /**
79     * This method bypasses `at_options_logging_on` check.
80     * It is intended to be used when we are sure we want to send logs to logstash and
81     * we are sure that we don't fire it off frequently. Good example of when we want to use this
82     * is during the site setup process
83     *
84     * @param string $message Log message.
85     * @param array  $extra   Optional. Additional log data. Defaults to empty array.
86     */
87    public static function unsafe_direct_log( $message, $extra = array() ) {
88        if ( ! self::$instance ) {
89            self::$instance = new self();
90        }
91        self::$instance->log( $message, $extra );
92    }
93
94    /**
95     * Constructor.
96     */
97    private function __construct() {
98        $this->siteurl = get_site_url();
99    }
100
101    /**
102     * Adds the log action.
103     */
104    private function add_hooks() {
105        add_action( 'wpcomsh_log', array( $this, 'log' ), 1 );
106    }
107
108    /**
109     * Logs a log message.
110     *
111     * @param string $message Log message.
112     * @param array  $extra   Optional. Additional log data. Defaults to empty array.
113     */
114    public function log( $message, $extra = array() ) {
115        $this->log_queue[] = array(
116            'message' => $message,
117            'extra'   => $extra,
118        );
119        if ( ! $this->has_shutdown_hook ) {
120            register_shutdown_function( array( $this, 'send_to_api' ) );
121            $this->has_shutdown_hook = true;
122        }
123    }
124
125    /**
126     * Sends log messages to the API endpoint.
127     */
128    public function send_to_api() {
129        if ( count( $this->log_queue ) > 0 ) {
130            $payload = array(
131                'siteurl'  => $this->siteurl,
132                'messages' => $this->log_queue,
133            );
134
135            wp_remote_post( self::$log_endpoint, array( 'body' => array( 'error' => wp_json_encode( $payload, JSON_UNESCAPED_SLASHES ) ) ) );
136        }
137    }
138}
139add_action( 'init', array( 'WPCOMSH_Log', 'init' ) );