Completed
Push — renovate/css-loader-3.x ( 28f4d8...69dcae )
by
unknown
51:11 queued 42:16
created

debug.php ➔ l_json_encode_pretty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Plugin Name: Automattic Debug Helpers
4
 * Description: <code>l( 'Code is Poetry' )</code>
5
 * Version: 1.0
6
 * Author: Automattic
7
 * Author URI: https://automattic.com/
8
 * Text Domain: jetpack
9
 *
10
 * @package Jetpack.
11
 */
12
13
// phpcs:disable WordPress.PHP.DevelopmentFunctions
14
15
/**
16
 * Sweet error logging
17
 *
18
 * The first call of l() will print an extra line containing a random ID & PID
19
 * and the script name or URL. The ID prefixes every l() log entry thereafter.
20
 * The extra line and ID will help you to identify and correlate log entries.
21
 *
22
 * l($something_to_log); // error_log(print_r($something_to_log, true));
23
 * l(compact('v1','v2'); // log several variables with labels
24
 * l($thing5, $thing10); // log two things
25
 * l();                  // log the file:line
26
 * l(null, $stuff, $ba); // log the file:line, then log two things.
27
 *
28
 * Example:
29
 *  wpsh> l('yo')
30
 *  wpsh> l('dude')
31
 * /tmp/php-errors:
32
 *  [21-Jun-2012 14:45:13] 1566-32201 => /home/wpcom/public_html/bin/wpshell/wpshell.php
33
 *  [21-Jun-2012 14:45:13] 1566-32201 yo
34
 *  [21-Jun-2012 14:50:23] 1566-32201 dude
35
 *
36
 * l() returns its input so you can safely wrap most kinds of expressions to log them.
37
 * l($arg1, $arg2) will call l($arg1) and l($arg2) and then return $arg1.
38
 *
39
 * A null argument will log the file and line number of the l() call.
40
 *
41
 * @param mixed $stuff Information to log.
42
 */
43
function l( $stuff = null ) {
44
	// Do nothing when debugging is off.
45
	if ( ! defined( 'WP_DEBUG' ) || WP_DEBUG === false ) {
46
		return $stuff;
47
	}
48
	static $pageload;
49
	// Call l() on each argument.
50
	if ( func_num_args() > 1 ) {
51
		foreach ( func_get_args() as $arg ) { // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
52
			l( $arg );
53
		}
54
		return $stuff;
55
	}
56
	if ( ! isset( $pageload ) ) {
57
		$pageload = substr( md5( wp_rand() ), 0, 4 );
58
		if ( ! empty( $_SERVER['argv'] ) ) {
59
			$hint = implode( ' ', $_SERVER['argv'] );
60
		} elseif ( isset( $_SERVER['HTTP_HOST'] ) && isset( $_SERVER['REQUEST_URI'] ) ) {
61
			$hint = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
62
		} else {
63
			$hint = php_sapi_name();
64
		}
65
		error_log( sprintf( '[%s-%s => %s]', $pageload, getmypid(), $hint ) );
66
	}
67
	$pid = $pageload . '-' . getmypid();
68
	if ( is_null( $stuff ) ) {
69
		// Log the file and line number.
70
		$backtrace = debug_backtrace( false ); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
71 View Code Duplication
		while ( isset( $backtrace[1]['function'] ) && __FUNCTION__ === $backtrace[1]['function'] ) {
72
			array_shift( $backtrace );
73
		}
74
		$log = sprintf( '%s line %d', $backtrace[0]['file'], $backtrace[0]['line'] );
75
	} elseif ( is_bool( $stuff ) ) {
76
		$log = $stuff ? 'TRUE' : 'FALSE';
77
	} elseif ( is_scalar( $stuff ) ) {
78
		// Strings and numbers can be logged exactly.
79
		$log = $stuff;
80
	} else {
81
		/*
82
		 * Are we in an output buffer handler?
83
		 * If so, print_r($stuff, true) is fatal so we must avoid that.
84
		 * This is not as slow as it looks: <1ms when !$in_ob_handler.
85
		 * Using json_encode_pretty() all the time is much slower.
86
		 */
87
		do {
88
			$in_ob_handler = false;
89
			$ob_status     = ob_get_status( true );
90
			$obs           = array();
91
92
			if ( ! $ob_status ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ob_status of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
93
				break;
94
			}
95
96
			foreach ( $ob_status as $ob ) {
97
				$obs[] = $ob['name'];
98
			}
99
			// This is not perfect: anonymous handlers appear as default.
100
			if ( array( 'default output handler' ) === $obs ) {
101
				break;
102
			}
103
			$backtrace = debug_backtrace( false ); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
104
			$bts       = array();
105
			foreach ( $backtrace as $level ) {
106
				$caller = '';
107
				if ( isset( $level['class'] ) ) {
108
					$caller = $level['class'] . '::';
109
				}
110
				$caller .= $level['function'];
111
				$bts[]   = $caller;
112
			}
113
			if ( array_intersect( $obs, $bts ) ) {
114
				$in_ob_handler = true;
115
			}
116
		} while ( false );
117
		if ( $in_ob_handler ) {
118
			$log = l_json_encode_pretty( $stuff );
119
		} else {
120
			$log = print_r( $stuff, true );
121
		}
122
	}
123
	error_log( sprintf( '[%s] %s', $pid, $log ) );
124
	return $stuff;
125
}
126
127
/**
128
 * Log only once (suppresses logging on subsequent calls from the same file+line).
129
 *
130
 * @param mixed $stuff Information to log.
131
 */
132
function lo( $stuff ) {
133
	static $callers = array();
134
	$args           = func_get_args();
135
	$backtrace      = debug_backtrace( false );
136
	$caller         = md5( $backtrace[0]['file'] . $backtrace[0]['line'] );
137
	if ( isset( $callers[ $caller ] ) ) {
138
		return $stuff;
139
	}
140
	$callers[ $caller ] = true;
141
	return call_user_func_array( 'l', $args );
142
}
143
144
/**
145
 * Pretty print for JSON (stolen from public.api)
146
 *
147
 * Previously, this function actually did stuff, but since JSON_PRETTY_PRINT is available as of PHP 5.4, let's use that.
148
 *
149
 * @param mixed $data Data to encode.
150
 *
151
 * @return false|string
152
 */
153
function l_json_encode_pretty( $data ) {
154
	return wp_json_encode( $data, JSON_PRETTY_PRINT );
155
}
156
157
/**
158
 * A timer.
159
 *
160
 * Call once to start, call again to stop. Returns a float.
161
 * Calling e($name) with different names permits simultaneous timers.
162
 *
163
 * e('stuff');
164
 * do_stuff();
165
 * $elapsed = e('stuff');
166
 *
167
 * @param string $name Timer name.
168
 *
169
 * @return mixed void or elapsed time.
170
 */
171
function e( $name = '' ) {
172
	static $times = array();
173
	if ( ! array_key_exists( $name, $times ) ) {
174
		$times[ $name ] = microtime( true );
175
		return;
176
	}
177
	$elapsed = microtime( true ) - $times[ $name ];
178
	unset( $times[ $name ] );
179
	return $elapsed;
180
}
181
182
/**
183
 * A wrapper for e() which also logs the result with l().
184
 *
185
 * Each log entry begins with a tag common to that pageload.
186
 * You can save a keystroke by calling e() then el().
187
 *
188
 * e($name);
189
 * do_stuff();
190
 * el($name);
191
 *
192
 * @param string $name Timer name.
193
 */
194
function el( $name = '' ) {
195
	$elapsed = e( $name );
196
	if ( null !== $elapsed ) {
197
		l( sprintf( "%9.6f e('%s')", $elapsed, $name ) );
198
	}
199
	return $elapsed;
200
}
201
202
/**
203
 * A persistent timer. After the initial call, each call to t()
204
 * will log the file:line and time elapsed since the initial call.
205
 */
206
function t() {
207
	static $start;
208
	$now = microtime( true );
209
	if ( ! isset( $start ) ) {
210
		$start = $now;
211
	}
212
213
	$backtrace = debug_backtrace( false );
214 View Code Duplication
	while ( isset( $backtrace[1]['function'] ) && __FUNCTION__ === $backtrace[1]['function'] ) {
215
		array_shift( $backtrace );
216
	}
217
218
	$file    = $backtrace[0]['file'];
219
	$line    = $backtrace[0]['line'];
220
	$format  = 't() => %9.6f at %s line %d';
221
	$elapsed = $now - $start;
222
	l( sprintf( $format, $elapsed, $file, $line ) );
223
}
224
225
// phpcs:enable
226