PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.8.23.5
Pods – Custom Content Types and Fields v2.8.23.5
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / tribe-common / src / Tribe / Log / File_Logger.php
pods / tribe-common / src / Tribe / Log Last commit date
Action_Logger.php 1 week ago Admin.php 1 week ago Canonical_Formatter.php 1 week ago File_Logger.php 1 week ago Logger.php 1 week ago Monolog_Logger.php 1 week ago Null_Logger.php 1 week ago Service_Provider.php 1 week ago
File_Logger.php
315 lines
1 <?php
2 /**
3 * Simple file based logging implementation.
4 *
5 * By default, this logger uses the system temporary directory for logging
6 * purposes and performs daily log rotation.
7 */
8 class Tribe__Log__File_Logger implements Tribe__Log__Logger {
9 protected $module_id = 'tribe_tmp_file_logger';
10 protected $log_dir = '';
11 protected $log_file = '';
12 protected $context = 'a';
13 protected $handle;
14
15 public function __construct() {
16 $this->set_log_dir();
17 $this->set_log_file();
18 }
19
20 public function __destruct() {
21 $this->close_handle();
22 }
23
24 protected function set_log_dir() {
25 /**
26 * Controls the directory used for logging.
27 *
28 * @var string $log_dir
29 */
30 $this->log_dir = apply_filters( 'tribe_file_logger_directory', get_temp_dir() );
31 }
32
33 /**
34 * Sets the path for the log file we're currently interested in using.
35 *
36 * @param string $date = null
37 */
38 protected function set_log_file( $date = null ) {
39 $this->log_file = $this->get_log_file_name( $date );
40 $this->obtain_handle();
41 }
42
43 /**
44 * Used to switch between contexts for reading ('r') and writing
45 * ('a' := append) modes.
46 *
47 * @see fopen() documentation
48 *
49 * @param string $context
50 */
51 protected function set_context( $context ) {
52 $this->context = $context;
53 $this->close_handle();
54 $this->obtain_handle();
55 }
56
57 /**
58 * Attempts to obtain a file handle for the current log file.
59 */
60 protected function obtain_handle() {
61 $this->close_handle();
62
63 if ( ! file_exists( $this->log_file ) && $this->is_available() ) {
64 touch( $this->log_file );
65 }
66
67 // Bail if we're attempting to write but don't have permission.
68 if ( 'r' !== $this->context && ! is_writable( $this->log_file ) ) {
69 return;
70 }
71
72 if ( is_readable( $this->log_file ) ) {
73 $this->handle = fopen( $this->log_file, $this->context );
74 }
75 }
76
77 /**
78 * Closes the current file handle, if one is open.
79 */
80 protected function close_handle() {
81 // is_resource() only returns true for open resources
82 if ( is_resource( $this->handle ) ) {
83 fclose( $this->handle );
84 }
85 }
86
87 /**
88 * Returns the log name to be used for reading/writing events for a specified date
89 * (defaulting to today, if no date is specified).
90 *
91 * @param string $date = null
92 *
93 * @return string
94 */
95 protected function get_log_file_name( $date = null ) {
96 if ( null === $date ) {
97 $date = date_i18n( 'Y-m-d' );
98 }
99
100 $filename = $this->log_dir . DIRECTORY_SEPARATOR . $this->get_log_file_basename() . $date . '.log';
101
102 /**
103 * Dictates the filename of the log used to record events for the specified date.
104 *
105 * @var string $filename
106 * @var string $date
107 */
108 return apply_filters( 'tribe_file_logger_filename', $filename, $date );
109 }
110
111 protected function get_log_file_basename() {
112 /**
113 * Log files share a common prefix, which aids identifying archived/rotated logs.
114 * This filter allows a degree of control to be exercised over the prefix to avoid
115 * conflicts, etc.
116 *
117 * @var string $log_file_base_name
118 */
119 return apply_filters( 'tribe_file_logger_file_prefix', $this->module_id . '_' );
120 }
121
122 /**
123 * Returns a 'human friendly' name for the logging implementation.
124 *
125 * @return string
126 */
127 public function get_name() {
128 return __( 'Default (uses temporary files)', 'tribe-common' );
129 }
130
131 /**
132 * Indicates if the logger will work in the current environment.
133 *
134 * @return bool
135 */
136 public function is_available() {
137 return is_writable( $this->log_dir ) && is_readable( $this->log_dir );
138 }
139
140 /**
141 * Responsible for commiting the entry to the log.
142 *
143 * @param string $entry
144 * @param string $type
145 * @param string $src
146 */
147 public function log( $entry, $type = Tribe__Log::DEBUG, $src = '' ) {
148 // Ensure we're in 'append' mode before we try to write
149 if ( 'a' !== $this->context ) {
150 $this->set_context( 'a' );
151 }
152
153 // Couldn't obtain the file handle? We'll bail out without causing further disruption
154 if ( ! $this->handle ) {
155 return;
156 }
157
158 fputcsv( $this->handle, [ date_i18n( 'Y-m-d H:i:s' ), $entry, $type, $src ] );
159 }
160
161 /**
162 * Retrieve up to $limit most recent log entries in reverse chronological
163 * order. If $limit is a negative or zero value, there is no limit.
164 *
165 * Supports passing a 'log' argument to recover
166 *
167 * @see Tribe__Log__Logger::list_available_logs()
168 *
169 * @param int $limit
170 * @param array $args
171 *
172 * @return array
173 */
174 public function retrieve( $limit = 0, array $args = [] ) {
175 // Ensure we're in 'read' mode before we try to retrieve
176 if ( 'r' !== $this->context ) {
177 $this->set_context( 'r' );
178 }
179
180 // Couldn't obtain the file handle? We'll bail out without causing further disruption
181 if ( ! $this->handle ) {
182 return [];
183 }
184
185 $rows = [];
186
187 while ( $current_row = fgetcsv( $this->handle ) ) {
188 if ( $limit && $limit === count( $rows ) ) {
189 array_shift( $rows );
190 }
191
192 $rows[] = $current_row;
193 }
194
195 return array_reverse( $rows );
196 }
197
198 /**
199 * Returns a list of currently accessible logs (current first, oldest last).
200 * Each is refered to by date.
201 *
202 * Example:
203 *
204 * [ '2016-12-31',
205 * '2016-12-30',
206 * '2016-12-30',
207 * '2016-12-30',
208 * '2016-12-30', ... ]
209 *
210 * @since 4.6.2 added extra safety checks before attempting to access log directory
211 *
212 * @return array
213 */
214 public function list_available_logs() {
215 $logs = [];
216
217 // This could be called when the log dir is not accessible.
218 if ( ! $this->is_available() ) {
219 return $logs;
220 }
221
222 $basename = $this->get_log_file_basename();
223
224 /**
225 * Though the is_available() method tests to see if the log directory is
226 * readable and writeable there are situations where that isn't a
227 * sufficient check by itself, hence the try/catch block.
228 *
229 * @see https://central.tri.be/issues/90436
230 */
231 try {
232 $log_files_dir = new DirectoryIterator( $this->log_dir );
233
234 // Look through the log storage directory
235 foreach ( $log_files_dir as $node ) {
236 if ( ! $node->isReadable() ) {
237 continue;
238 }
239
240 $name = $node->getFilename();
241 $ext = $node->getExtension();
242
243 // Skip unless it is a .log file with the expected prefix
244 if ( 'log' !== $ext || 0 !== strpos( $name, $basename ) ) {
245 continue;
246 }
247
248 if ( preg_match( '/([0-9]{4}\-[0-9]{2}\-[0-9]{2})/', $name, $matches ) ) {
249 $logs[] = $matches[1];
250 }
251 }
252
253 rsort( $logs );
254 } catch ( Exception $e ) {
255 return $logs;
256 }
257
258 return $logs;
259 }
260
261 /**
262 * Switches to the specified log. The $log_identifier should take the
263 * form of a "yyyy-mm-dd" format date string.
264 *
265 * If optional param $create is true then it will try to create a log
266 * using the provided identifier. If the log does not exist, cannot be
267 * created or an invalid identifier has been passed in then boolean false
268 * will be returned, otherwise it will attempt to switch to the new log.
269 *
270 * @param mixed $log_identifier
271 * @param bool $create
272 *
273 * @return bool
274 */
275 public function use_log( $log_identifier, $create = false ) {
276 $log_file = $this->get_log_file_name( $log_identifier );
277 $exists = file_exists( $log_file );
278
279 if ( ! $exists && ! $create ) {
280 return false;
281 }
282
283 if ( ! $exists && $create && preg_match( '/^([0-9]{4}\-[0-9]{2}\-[0-9]{2})$/', $log_file ) ) {
284 if ( false === file_put_contents( $log_file, '' ) ) {
285 return false;
286 }
287 }
288
289 $this->set_log_file( $log_identifier );
290 return true;
291 }
292
293 /**
294 * Performs routine maintenance and cleanup work (such as log rotation)
295 * whenever it is called.
296 */
297 public function cleanup() {
298 // Default to retaining 7 days worth of logs
299 $cutoff = date_i18n( 'Y-m-d', current_time( 'timestamp' ) - WEEK_IN_SECONDS );
300
301 /**
302 * Logs falling on or earlier than this date will be removed.
303 *
304 * @param string $cutoff 'Y-m-d' format date string
305 */
306 $cutoff = apply_filters( 'tribe_file_logger_cutoff', $cutoff );
307
308 foreach ( $this->list_available_logs() as $available_log ) {
309 if ( $available_log <= $cutoff ) {
310 unlink( $this->get_log_file_name( $available_log ) );
311 }
312 }
313 }
314 }
315