PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.9.16
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.9.16
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
woocommerce-pos / includes / Logger.php

Logger.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.9.16, at includes/Logger.php

212 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Logger.
4 *
5 * @package WCPOS\WooCommercePOS
6 */
7
8 namespace WCPOS\WooCommercePOS;
9
10 use function is_string;
11
12 /**
13 * Class Logger
14 *
15 * NOTE: do not put any SQL queries in this class, eg: options table lookup
16 */
17 class Logger {
18 public const WC_LOG_FILENAME = 'woocommerce-pos';
19
20 /**
21 * Logger instance.
22 *
23 * @var \WC_Logger_Interface|null
24 */
25 public static $logger;
26
27 /**
28 * Log level.
29 *
30 * @var string|null
31 */
32 public static $log_level;
33
34 /**
35 * Hash of the last logged message (level + message + context) for dedup.
36 *
37 * @var string|null
38 */
39 private static ?string $last_message_hash = null;
40
41 /**
42 * Log level of the last deduplicated message, so flush writes at the correct level.
43 *
44 * @var string|null
45 */
46 private static ?string $last_message_level = null;
47
48 /**
49 * Number of consecutive duplicate messages suppressed.
50 *
51 * @var int
52 */
53 private static int $repeat_count = 0;
54
55 /**
56 * Whether the shutdown flush hook has been registered.
57 *
58 * @var bool
59 */
60 private static bool $shutdown_registered = false;
61
62 /**
63 * Set the log level.
64 *
65 * @param string $level The log level.
66 */
67 public static function set_log_level( $level ): void {
68 self::$log_level = $level;
69 }
70
71 /**
72 * Utilize WC logger class.
73 *
74 * Suppresses consecutive duplicate messages within the same request.
75 * When a different message arrives, any suppressed count is flushed
76 * as "Previous message repeated N more times".
77 *
78 * @param mixed $message The message to log.
79 * @param mixed $context Optional additional context data to log.
80 */
81 public static function log( $message, $context = null ): void {
82 if ( ! class_exists( 'WC_Logger' ) ) {
83 return;
84 }
85
86 if ( is_null( self::$log_level ) ) {
87 self::$log_level = 'info';
88 }
89
90 if ( ! is_string( $message ) ) {
91 $message = print_r( $message, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
92 }
93
94 $context_string = '';
95 if ( null !== $context ) {
96 $context_string = is_string( $context ) ? $context : print_r( $context, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
97 }
98
99 // Build a hash from level + message + context to detect duplicates.
100 $hash = md5( self::$log_level . '|' . $message . '|' . $context_string );
101
102 if ( null !== self::$last_message_hash && $hash === self::$last_message_hash ) {
103 ++self::$repeat_count;
104
105 return;
106 }
107
108 // Different message — flush any pending repeat count first.
109 self::flush_repeat_count();
110
111 // Now log the new message.
112 self::$last_message_hash = $hash;
113 self::$last_message_level = self::$log_level;
114 self::$repeat_count = 0;
115
116 $full_message = $message;
117 if ( '' !== $context_string ) {
118 $full_message .= ' | Context: ' . $context_string;
119 }
120
121 self::write_log( $full_message );
122 }
123
124 /**
125 * Flush any pending repeat count to the log.
126 *
127 * Called when a new (different) message arrives, or at shutdown
128 * to ensure the final repeat count is written.
129 */
130 public static function flush_repeat_count(): void {
131 if ( self::$repeat_count > 0 ) {
132 $saved_level = self::$log_level;
133 self::$log_level = self::$last_message_level ?? 'info';
134
135 self::write_log(
136 sprintf( 'Previous message repeated %d more time(s)', self::$repeat_count )
137 );
138
139 self::$log_level = $saved_level;
140 self::$repeat_count = 0;
141 }
142 }
143
144 /**
145 * Reset deduplication state.
146 *
147 * Used by tests to ensure clean state between test methods.
148 */
149 public static function reset_dedup_state(): void {
150 self::$last_message_hash = null;
151 self::$last_message_level = null;
152 self::$repeat_count = 0;
153 self::$shutdown_registered = false;
154 }
155
156 /**
157 * Log a warning message.
158 *
159 * @param mixed $message The message to log.
160 * @param mixed $context Optional additional context data.
161 */
162 public static function warning( $message, $context = null ): void {
163 $previous_level = self::$log_level;
164 self::$log_level = 'warning';
165 self::log( $message, $context );
166 self::$log_level = $previous_level;
167 }
168
169 /**
170 * Log an error message.
171 *
172 * @param mixed $message The message to log.
173 * @param mixed $context Optional additional context data.
174 */
175 public static function error( $message, $context = null ): void {
176 $previous_level = self::$log_level;
177 self::$log_level = 'error';
178 self::log( $message, $context );
179 self::$log_level = $previous_level;
180 }
181
182 /**
183 * Write a message to the WC logger, applying the logging filter.
184 *
185 * Registers a shutdown hook on first write to flush any remaining
186 * repeat count at end of request.
187 *
188 * @param string $message The formatted message to write.
189 */
190 private static function write_log( string $message ): void {
191 if ( ! apply_filters( 'woocommerce_pos_logging', true, $message ) ) {
192 return;
193 }
194
195 if ( ! isset( self::$logger ) ) {
196 self::$logger = wc_get_logger();
197 }
198
199 self::$logger->log( self::$log_level, $message, array( 'source' => self::WC_LOG_FILENAME ) );
200
201 if ( ! self::$shutdown_registered ) {
202 self::$shutdown_registered = true;
203 add_action(
204 'shutdown',
205 function () {
206 Logger::flush_repeat_count();
207 }
208 );
209 }
210 }
211 }
212