logger = $logger; } /** * Write a PSR-3 log record to the WooCommerce logger. * * Best-effort: any failure while formatting or writing (e.g. a throwing * Stringable message, or wc_get_logger() being unavailable) is swallowed so * logging can never break the SDK operation that emitted the line. * * @param mixed $level PSR-3 level (one of LogLevel::*). * @param string|\Stringable $message Message, optionally with {placeholders}. * @param array $context Context values for placeholder interpolation. * @return void */ public function log( $level, string|\Stringable $message, array $context = array() ): void { // Respect the same merchant "enable logging" toggle the legacy path uses. if ( ! $this->logger->is_enabled() ) { return; } try { $level = $this->normalize_level( $level ); $message = self::TAG . ' ' . $this->interpolate( (string) $message, $context ); // Source is merged last so incoming context can never redirect the // entry away from the plugin's shared WC log channel. $wc_context = array_merge( $context, array( 'source' => self::SOURCE ) ); $wc_logger = wc_get_logger(); if ( $wc_logger ) { $wc_logger->log( $level, $message, $wc_context ); } } catch ( \Throwable $e ) { // Swallowed deliberately — logging is best-effort and must not propagate. return; } } /** * Coerce an arbitrary level into a value WC_Logger accepts. * * @param mixed $level Incoming PSR-3 level. * @return string A valid WC log level; notice when unrecognised. */ private function normalize_level( $level ): string { $level = is_string( $level ) ? strtolower( $level ) : ''; return in_array( $level, self::VALID_LEVELS, true ) ? $level : LogLevel::NOTICE; } /** * Interpolate {placeholder} tokens from context, per the PSR-3 spec. * * Only context values that can be cast to a string are substituted; other * values (arrays, non-stringable objects) leave their placeholder intact. * * @param string $message Raw message. * @param array $context Context values. * @return string */ private function interpolate( string $message, array $context ): string { if ( empty( $context ) || false === strpos( $message, '{' ) ) { return $message; } $replacements = array(); foreach ( $context as $key => $value ) { if ( is_scalar( $value ) || $value instanceof \Stringable ) { $replacements[ '{' . $key . '}' ] = (string) $value; } } return strtr( $message, $replacements ); } }