Last active
September 4, 2026 21:29
-
-
Save aklump/a90467ce56d3f555c2af6f8c9a11e159 to your computer and use it in GitHub Desktop.
#ClassLoggerTrait.php# Provides class-scoped logging helpers for Drupal custom classes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace Drupal\JIG__EXTENSION_NAME\Logger; | |
| use Psr\Log\LoggerInterface; | |
| use Psr\Log\LogLevel; | |
| /** | |
| * Provides class-scoped logging helpers. | |
| * | |
| * Classes using this trait get a class logger channel derived from the | |
| * consuming class name. The channel uses the short class name so Drupal's log | |
| * UI remains easy to scan and filter. Long class names are shortened and given | |
| * a stable hash suffix to stay within watchdog channel length limits while | |
| * reducing collision risk. | |
| * | |
| * These helpers are intentionally static. The logger channel is derived from | |
| * static::class, not object state, and some Drupal extension points such as | |
| * entity callbacks and static utility methods need to log when no object | |
| * instance is available. Instance methods can still call these helpers with | |
| * static::classLogger() or static::logClassException(). | |
| * | |
| * The class logger channel name is public so callers can use the same | |
| * class-derived channel with Drupal's logging APIs directly when they need | |
| * behavior not provided by this trait. | |
| * | |
| * The exception helper also provides a single migration point from Drupal 9's | |
| * watchdog_exception() to \Drupal\Core\Utility\Error::logException(). Callers | |
| * should use static::logClassException() instead of calling either API directly | |
| * when class-scoped exception logging is sufficient; the implementation can | |
| * then switch to Drupal's newer exception logging API without changing | |
| * consuming classes. | |
| * | |
| * The exception helper is intentionally lightweight and PSR-3 oriented. It is | |
| * intended for quick, severity-aware exception logging during normal | |
| * application flow. Use \Drupal\Core\Utility\Error::logException() directly | |
| * when Drupal's full exception logging format is required. | |
| */ | |
| trait ClassLoggerTrait { | |
| /** | |
| * Gets the logger channel name for the calling class. | |
| * | |
| * The short class name is used because Drupal's log UI exposes the channel as | |
| * a primary scanning/filtering column. Long names are shortened with a hash | |
| * suffix to avoid watchdog channel length issues while reducing collision | |
| * risk. | |
| */ | |
| public static function classLoggerChannelName(): string { | |
| static $channels = []; | |
| $class = static::class; | |
| if (!isset($channels[$class])) { | |
| $namespace_position = strrpos($class, '\\'); | |
| $short_name = $namespace_position === FALSE | |
| ? $class | |
| : substr($class, $namespace_position + 1); | |
| if (strlen($short_name) > 32) { | |
| $short_name = substr($short_name, 0, 25) . '_' . substr(hash('crc32b', $class), 0, 6); | |
| } | |
| $channels[$class] = $short_name; | |
| } | |
| return $channels[$class]; | |
| } | |
| /** | |
| * Gets a logger instance set to this class's logger channel. | |
| * | |
| * Intentionally do not statically cache the classLogger factory. Drupal's | |
| * container already returns shared and/or optimized service instances, and | |
| * keeping our own copy can make tests/container rebuilds harder to reason | |
| * about for negligible gain. | |
| */ | |
| protected static function classLogger(): LoggerInterface { | |
| return \Drupal::logger(static::classLoggerChannelName()); | |
| } | |
| /** | |
| * Logs an exception using the class-derived logger channel. | |
| * | |
| * @param \Throwable $exception | |
| * The exception or error to log. | |
| * @param string $level | |
| * A PSR-3 log level from \Psr\Log\LogLevel. | |
| * @param array $context | |
| * Additional context variables for the log message. | |
| */ | |
| protected static function logClassException(\Throwable $exception, string $level = LogLevel::ERROR, array $context = []): void { | |
| if ($exception instanceof \Exception) { | |
| watchdog_exception(static::classLoggerChannelName(), $exception, NULL, $context, $level); | |
| return; | |
| } | |
| // Drupal 9's watchdog_exception() only accepts \Exception. Log other | |
| // \Throwable instances directly until this can use Error::logException(). | |
| $context += [ | |
| 'exception' => $exception, | |
| '@type' => get_class($exception), | |
| '@message' => $exception->getMessage(), | |
| '@file' => $exception->getFile(), | |
| '@line' => $exception->getLine(), | |
| ]; | |
| static::classLogger() | |
| ->log($level, '@type: @message in @file on line @line', $context); | |
| // TODO Drupal 10+: replace this method body with: | |
| // \Drupal\Core\Utility\Error::logException(static::classLogger(), $exception, \Drupal\Core\Utility\Error::DEFAULT_ERROR_MESSAGE, $context, $level); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment