PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.18.2
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.18.2
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / classes / WordPress / Settings / Logger.php
nitropack / classes / WordPress / Settings Last commit date
Components.php 1 year ago Logger.php 1 year ago Shortcodes.php 1 year ago TestMode.php 1 year ago
Logger.php
319 lines
1 <?php
2
3 namespace NitroPack\WordPress\Settings;
4
5 /**
6 * Logger Class for NitroPack WordPress plugin
7 *
8 * This class provides logging functionality with different log levels
9 */
10 class Logger {
11 /**
12 * @var mixed $siteConfig Configuration settings for the site.
13 * @var string $archive_zip_name Name of the archive zip file for logs.
14 * @var string $log_file_extension Extension of the log files.
15 */
16 public $siteConfig;
17 public $archive_zip_name;
18 public $log_file_extension;
19
20 public function __construct( $config ) {
21
22 add_action( 'wp_ajax_nitropack_set_log_level_ajax', [ $this, 'nitropack_set_log_level_ajax' ] );
23 add_action( 'wp_ajax_nitropack_archive_logs_ajax', [ $this, 'nitropack_archive_logs_ajax' ] );
24 add_action( 'wp_ajax_nitropack_download_log_ajax', [ $this, 'nitropack_download_log_ajax' ] );
25
26 $this->siteConfig = $config;
27 $this->archive_zip_name = 'nitropack_logs.zip';
28 $this->log_file_extension = 'csv';
29 }
30 /**
31 * Render the logger settings in System Report
32 */
33 public function render() {
34 $components = new Components();
35 $siteConfig = nitropack_get_site_config();
36 $minimumLogLevel = $siteConfig['minimumLogLevel'];
37 ?>
38 <div class="flex">
39 <div class="" style="flex-basis: 80%;">
40 <h3><?php esc_html_e( 'Generate Log File', 'nitropack' ); ?></h3>
41 <p><?php esc_html_e( 'Logs keep track of what is happening on your site—like when plugins are installed, posts are published, or something goes wrong. They\'re great for finding and fixing tricky problems, especially with our support\'s help. Logs are saved for up to 14 days.', 'nitropack' ); ?>
42 <a href="https://support.nitropack.io/en/articles/10243831-how-to-use-the-generate-log-file-feature-in-your-wordpress-dashboard"
43 target="_blank"><?php esc_html_e( 'Learn more', 'nitropack' ); ?></a>
44 </p>
45 </div>
46 <div class="ml-auto">
47 <?php $components->render_toggle( 'minimum-log-level-status', $minimumLogLevel ); ?>
48 </div>
49 </div>
50 <div class="logging<?php echo $minimumLogLevel ? '' : ' hidden'; ?>">
51 <div class="select-log-level">
52 <h4><?php esc_html_e( 'Select log level', 'nitropack' );
53 $components->render_tooltip( 'select-log-level', 'Select and generate log output by categorizing messages based on their urgency.' ); ?>
54 </h4>
55 <div class="radio-options-group">
56 <?php $components->render_fancy_radio( 3, 'set-log-level-error', 'set-log-level', $minimumLogLevel === 3 ? true : false, esc_html__( 'Minimal (Errors Only)', 'nitropack' ), esc_html__( 'Perfect for live websites where you can quickly spot and address serious issues without unnecessary noise.', 'nitropack' ) );
57 $components->render_fancy_radio( 2, 'set-log-level-info', 'set-log-level', $minimumLogLevel === 2 ? true : false, esc_html__( 'Moderate (Errors & Actions)', 'nitropack' ), esc_html__( 'Best used during site maintenance or troubleshooting to get a clearer view of your site\'s activities.', 'nitropack' ) );
58 $components->render_fancy_radio( 1, 'set-log-level-info', 'set-log-level', $minimumLogLevel === 1 ? true : false, esc_html__( 'Detailed (Errors, Actions & Full Details)', 'nitropack' ), esc_html__( 'Great when debugging issues with our support team. Avoid using it constantly as it is very detailed and may fill up quickly.', 'nitropack' ) ); ?>
59 </div>
60 </div>
61
62 <div class="log-table-container">
63 <table id="log-table">
64 <thead>
65 <tr>
66 <th><?php esc_html_e( 'Log Name', 'nitropack' ); ?></th>
67 <th><?php esc_html_e( 'File size', 'nitropack' ); ?></th>
68 <th><?php esc_html_e( 'Date added', 'nitropack' ); ?></th>
69 <th class="hidden"><?php esc_html_e( 'Action', 'nitropack' ); ?></th>
70 </tr>
71 </thead>
72 <tbody>
73 <?php if ( is_dir( NITROPACK_LOGS_DATA_DIR ) ) :
74 $files = scandir( NITROPACK_LOGS_DATA_DIR );
75 $files = array_filter( $files, function ($file) {
76 return pathinfo( $file, PATHINFO_EXTENSION ) === $this->log_file_extension;
77 } );
78
79 // Sort files by modification time, newest first
80 usort( $files, function ($a, $b) {
81 $filePathA = NITROPACK_LOGS_DATA_DIR . '/' . $a;
82 $filePathB = NITROPACK_LOGS_DATA_DIR . '/' . $b;
83 return filemtime( $filePathB ) - filemtime( $filePathA );
84 } );
85 if ( ! empty( $files ) ) :
86 $fileDates = [];
87 foreach ( $files as $file ) :
88 $filePath = NITROPACK_LOGS_DATA_DIR . '/' . $file;
89 $fileURL = $this->get_logs_dir_url() . $file;
90 $fileSize = filesize( $filePath );
91 $fileDate = date( "F d, Y H:i", filemtime( $filePath ) );
92 $fileDates[] = filemtime( $filePath );
93 $fileDateParts = explode( ' ', $fileDate );
94 $datePart = implode( ' ', array_slice( $fileDateParts, 0, 3 ) );
95 $timePart = $fileDateParts[3]; ?>
96 <tr>
97 <td class="file"><a href="<?php echo esc_url( $fileURL ); ?>"
98 target="_blank"><?php echo esc_html( $file ); ?></a></td>
99 <td class="file-size"><?php echo esc_html( size_format( $fileSize ) ); ?></td>
100 <td class="file-date"><?php echo "{$datePart} <div class='time'>{$timePart}</div>"; ?></td>
101 <td class="action hidden"><?php $components->render_button( [
102 'text' => 'Download',
103 'type' => 'a',
104 'href' => esc_url( $fileURL ),
105 'icon' => 'download.svg',
106 'classes' => 'btn btn-secondary download-log',
107 'attributes' => [ 'download' => '' ]
108 ] ); ?></td>
109 </tr>
110 <?php endforeach;
111 else :
112 echo '<tr class="no-logs"><td colspan="4">' . esc_html__( 'No error logs yet.', 'nitropack' ) . '</td></tr>';
113 endif;
114 else :
115 echo '<tr class="no-logs"><td colspan="4">' . esc_html__( 'No error logs yet.', 'nitropack' ) . '</td></tr>';
116 endif; ?>
117 </tbody>
118 </table>
119 </div>
120 <?php
121 if ( ! empty( $fileDates ) ) {
122 rsort( $fileDates );
123 $latestDate = date( "F d, Y", $fileDates[0] );
124 $earliestDate = date( "F d, Y", end( $fileDates ) );
125 ?>
126 <div class="download-all-logs">
127 <div>
128 <h3><?php esc_html_e( 'Download all logs', 'nitropack' ); ?></h3>
129 <p><?php printf( esc_html__( 'Download usage for %1$s - %2$s', 'nitropack' ), esc_html( $earliestDate ),
130 esc_html( $latestDate )
131 ); ?>
132 </p>
133 </div>
134 <?php if ( class_exists( 'ZipArchive' ) ) {
135 $components->render_button( [
136 'text' => 'Download all (.zip)',
137 'type' => 'a',
138 'href' => '',
139 'icon' => 'download.svg',
140 'classes' => 'btn btn-secondary archive-logs',
141 'attributes' => [ 'download' => '' ]
142 ] );
143 } else {
144 $components->render_button( [
145 'text' => 'Download all (.zip)',
146 'type' => 'a',
147 'href' => '',
148 'icon' => 'download.svg',
149 'classes' => 'btn btn-secondary archive-logs disabled',
150 ] );
151 } ?>
152 </div>
153 <?php if ( ! class_exists( 'ZipArchive' ) ) {
154 $components->render_notification( esc_html__( 'Bulk log downloads aren\'t available because the PHP ext-zip isn\'t enabled. Contact your hosting provider or download files individually.', 'nitropack' ), 'error' );
155 } ?>
156 <?php } ?>
157 </div>
158 <?php
159 }
160
161 /**
162 * Handles the AJAX request to set the log level for NitroPack.
163 *
164 * This method verifies the AJAX nonce, retrieves the minimum log level from the POST request,
165 * updates the site configuration with the new log level, and returns a JSON response indicating
166 * success or failure.
167 * $minimumLogLevel is set to 1 for info logs and 2 for error logs, and null if the log level is not set.
168 * @return void
169 */
170 public function nitropack_set_log_level_ajax() {
171 nitropack_verify_ajax_nonce( $_REQUEST );
172
173 $minimumLogLevel = isset( $_POST['minimum_log_level'] ) ? $_POST['minimum_log_level'] : null;
174
175 if ( $minimumLogLevel && is_numeric( $minimumLogLevel ) ) {
176 $minimumLogLevel = (int) $minimumLogLevel;
177 } else {
178 $minimumLogLevel = null;
179 }
180
181 $siteConfig = $this->siteConfig->get();
182 $configKey = \NitroPack\WordPress\NitroPack::getConfigKey();
183 $siteConfig[ $configKey ]['minimumLogLevel'] = $minimumLogLevel;
184
185 //store it as null or integer in config.json
186 $config_updated = $this->siteConfig->set( $siteConfig );
187
188 //store it as empty string or numeric string in the database
189 if ( $minimumLogLevel === null ) {
190 $minimumLogLevel = '';
191 }
192 $updated = update_option( 'nitropack_minimumLogLevel', $minimumLogLevel );
193 if ( $config_updated && $updated ) {
194
195 nitropack_json_and_exit( array( "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ) ) );
196 } else {
197 nitropack_json_and_exit( array(
198 "type" => "error",
199 "message" => nitropack_admin_toast_msgs( 'error' )
200 ) );
201 }
202 }
203
204 /**
205 * Archives log files into a zip archive and returns the archive URL via AJAX.
206 *
207 * This function is triggered via an AJAX request and performs the following steps:
208 * 1. Verifies the AJAX nonce.
209 * 2. Creates a new ZipArchive instance.
210 * 3. Iterates through the log files in the specified directory and stores mmodification date
211 * 4. Filters out non-csv files, checks if the file has been modified and adds it to the zip archive.
212 * 5. Closes the zip archive.
213 * 6. Returns a success message and the archive URL if the process is successful.
214 * 7. Returns an error message if any step fails.
215 *
216 * @return void
217 */
218
219 public function nitropack_archive_logs_ajax() {
220 nitropack_verify_ajax_nonce( $_REQUEST );
221
222 $zip = new \ZipArchive();
223 $archivePath = $this->get_archive_zip_path();
224
225 if ( $zip->open( $archivePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE ) === TRUE ) {
226 $files = new \RecursiveIteratorIterator(
227 new \RecursiveDirectoryIterator( NITROPACK_LOGS_DATA_DIR ),
228 \RecursiveIteratorIterator::LEAVES_ONLY
229 );
230
231 // Store the modification times of the existing files in the ZIP archive
232 $existingFiles = [];
233 for ( $i = 0; $i < $zip->numFiles; $i++ ) {
234 $stat = $zip->statIndex( $i );
235 $existingFiles[ $stat['name'] ] = $stat['mtime'];
236 }
237
238 foreach ( $files as $name => $file ) {
239 if ( ! $file->isDir() ) {
240 $filePath = $file->getRealPath();
241 $relativePath = substr( $filePath, strlen( NITROPACK_LOGS_DATA_DIR ) );
242
243 // Filter out non-csv files
244 if ( pathinfo( $filePath, PATHINFO_EXTENSION ) !== $this->log_file_extension )
245 continue;
246
247 // Check if the file has been modified
248 $fileMTime = filemtime( $filePath );
249 if ( ! isset( $existingFiles[ $relativePath ] ) || $fileMTime > $existingFiles[ $relativePath ] ) {
250 if ( ! $zip->addFile( $filePath, $relativePath ) ) {
251 error_log( "Failed to add file: $filePath" );
252 nitropack_json_and_exit( array(
253 "type" => "error",
254 "message" => nitropack_admin_toast_msgs( 'error' )
255 ) );
256 }
257 }
258 }
259 }
260
261 if ( ! $zip->close() ) {
262 error_log( "Failed to close zip archive: " . $archivePath );
263 nitropack_json_and_exit( array(
264 "type" => "error",
265 "message" => nitropack_admin_toast_msgs( 'error' )
266 ) );
267 }
268
269 // Check if the archive file exists
270 if ( file_exists( $archivePath ) ) {
271 $archive_url = $this->get_archive_url();
272 error_log( "Archive URL: " . $archive_url );
273
274 nitropack_json_and_exit( array( "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ), "url" => $archive_url ) );
275 } else {
276 error_log( "Archive file does not exist: " . $archivePath );
277 nitropack_json_and_exit( array(
278 "type" => "error",
279 "message" => nitropack_admin_toast_msgs( 'error' )
280 ) );
281 }
282 } else {
283 error_log( "Failed to open zip archive: " . $archivePath );
284 nitropack_json_and_exit( array(
285 "type" => "error",
286 "message" => nitropack_admin_toast_msgs( 'error' )
287 ) );
288 }
289 }
290 /**
291 * Gets the url of the log dir
292 * Example: https://website.com/wp-content/wp-content/uploads/nitropack-logs/
293 * Use the filter if you have changed the constant NITROPACK_LOGS_DATA_DIR
294 * @return string
295 */
296 public function get_logs_dir_url() {
297 $dir_url = content_url() . '/uploads/nitropack-logs/';
298 return apply_filters( 'nitropack_logs_dir_url', $dir_url );
299 }
300 /**
301 * Gets the path of the nitropack_logs.zip
302 * Example: /var/www/html/wp-content/uploads/nitropack-logs/nitropack_logs.zip
303 * @return string
304 */
305 private function get_archive_zip_path() {
306 $path = NITROPACK_LOGS_DATA_DIR . $this->archive_zip_name;
307 return $path;
308 }
309 /**
310 * Gets the path of the nitropack_logs.zip
311 * Example: https://website.com/wp-content/uploads/nitropack-logs/nitropack_logs.zip
312 * @return string
313 */
314 private function get_archive_url() {
315 $url = $this->get_logs_dir_url() . $this->archive_zip_name;
316 return $url;
317 }
318 }
319