Обновление модулей кеширования и логирования

В разрабатываемой версии мы переработали модули Cache и Logger — код стал проще, меньше и более функционален.

Модуль кеширования (Cache)
Реализован новый принцип работы с разными бекендами, теперь каждый бекенд представляет из себя отдельную сущность (наследуется от ModuleCache_EntityBackend). Такой подход позволяет легко добавлять новые типы бекендов — достаточно создать сущность с нужным типом кеша, например, вот так выглядит XCache:
/**
 * Бекенд xcache
 */
class ModuleCache_EntityBackendXcache extends ModuleCache_EntityBackend {
	/**
	 * Проверяет доступность использования текущего бекенда
	 *
	 * @return mixed
	 */
	public function IsAvailable() {
		if (extension_loaded('xcache')) {
			return true;
		}
		return 'The xcache extension must be loaded for using this backend!';
	}
	/**
	 * Проверяет доступность использование мульти-get запросов к кешу (указывать сразу несколько ключей)
	 *
	 * @return mixed
	 */
	public function IsAllowMultiGet() {
		return true;
	}
	/**
	 * Инициализация бекенда
	 *
	 * @param array $aParams
	 *
	 * @return mixed
	 */
	public function Init($aParams=array()) {
		require_once(LS_DKCACHE_PATH.'Cache/Backend/TagEmuWrapper.php');
		require_once(LS_DKCACHE_PATH.'Zend/Cache/Backend/Xcache.php');
		$aConfig=Config::Get('xcache');

		$oCahe = new Zend_Cache_Backend_Xcache(is_array($aConfig) ? $aConfig : array());
		if (isset($aParams['stats_callback'])) {
			$this->oCacheBackend=new Dklab_Cache_Backend_TagEmuWrapper(new Dklab_Cache_Backend_Profiler($oCahe,$aParams['stats_callback']));
		} else {
			$this->oCacheBackend=new Dklab_Cache_Backend_TagEmuWrapper($oCahe);
		}
	}
	/**
	 * Получить значение из кеша
	 *
	 * @param string $sName	Имя ключа
	 * @return mixed|bool
	 */
	public function Get($sName) {
		return $this->oCacheBackend->load($sName);
	}
	/**
	 * Записать значение в кеш
	 *
	 * @param  mixed  $mData	Данные для хранения в кеше
	 * @param  string $sName	Имя ключа
	 * @param  array  $aTags	Список тегов, для возможности удалять сразу несколько кешей по тегу
	 * @param  int|bool    $iTimeLife	Время жизни кеша в секундах
	 * @return bool
	 */
	public function Set($mData,$sName,$aTags=array(),$iTimeLife=false) {
		return $this->oCacheBackend->save($mData,$sName,$aTags,$iTimeLife);
	}
	/**
	 * Удаляет значение из кеша по ключу(имени)
	 *
	 * @param string $sName	Имя ключа
	 * @return bool
	 */
	public function Delete($sName) {
		return $this->oCacheBackend->remove($sName);
	}
	/**
	 * Чистит кеши
	 *
	 * @param string $cMode	Режим очистки кеша
	 * @param array $aTags	Список тегов, актуально для режима Zend_Cache::CLEANING_MODE_MATCHING_TAG
	 * @return bool
	 */
	public function Clean($cMode=Zend_Cache::CLEANING_MODE_ALL,$aTags=array()) {
		return $this->oCacheBackend->clean($cMode,$aTags);
	}
}

На данный момент в стандартном комплекте идет поддержка File, XCache и Memcached. Также добавлены дополнительные бекенды — FileOrm и Life. FileOrm служит для отдельного файлового кеширования схем таблиц в БД, автоматически применяется в функционале ORM. Life — это сохранение данных на время выполнения скрипта, т.е. аналог паттерна Registry. Применяется он в методах GetLife и SetLife.

Появилась возможность явно указывать тип используемого бекенда в методах работы с кешем (параметр $sCacheType). И возможность принудительно использовать кеш, даже если он отключен в конфиге (параметр $bForce). Вот так сейчас выглядит метод Set:
	 /**
	 * Записать значение в кеш
	 *
	 * @param  mixed  $mData	Данные для хранения в кеше
	 * @param  string $sName	Имя ключа
	 * @param  array|string  $aTags	Список тегов, для возможности удалять сразу несколько кешей по тегу
	 * @param  int|bool    $iTimeLife	Время жизни кеша в секундах
	 * @param string|null $sCacheType	Тип кеша
	 * @param bool $bForce	Принудительно использовать кеширование, даже если оно отключено в конфиге
	 *
	 * @return bool
	 */
	public function Set($mData,$sName,$aTags=array(),$iTimeLife=false,$sCacheType=null,$bForce=false) {
		...
	}

А для метода Get добавился еще и третий новый параметр — $bKeepInMemory. Если он = true, то данные после получения из кеша будут дополнительно складываться в оперативную память на время выполнения скрипта, а при повторном обращении к методу Get уже будут браться из памяти, минуя запрос к бекенду кеша. Такой подход позволяет ускорить работу при многократном обращении к редко обновляемым одним и тем же данным.
	 /**
	 * Получить значение из кеша
	 *
	 * @param string|array $sName	Имя ключа
	 * @param string|null $sCacheType	Тип кеша
	 * @param bool $bForce	Принудительно использовать кеширование, даже если оно отключено в конфиге
	 * @param bool $bKeepInMemory	Если true, то данные дополнительно будут сохранены в памяти на время выполнения запроса (скрипта).
	 * 								В результате чего повторные Get() запросы к кешу будут значительно быстрее. Параметр не поддерживает мульти-запросы к кешу.
	 * 								Данные параметр следует использовать очень осторожно, т.к. кешированные данные нельзя будет обновить/удалить до конца выполнения запроса.
	 *
	 * @return mixed|bool
	 */
	public function Get($sName,$sCacheType=null,$bForce=false,$bKeepInMemory=false) {
		...
	}


Модуль логирования (Logger)
Функционал логирования полностью переписан и теперь базируется на использовании библиотеки Monolog. Это дает широкие и гибкие возможности настройки всего процесса логирования, от формата логов до места их хранения(файлы, БД и т.п.).
В LS по дефолту используются несколько инстансов (потоков) логов, каждый со своим предназначением и местом хранения. Дефолтные инстансы: default, db_query, db_error, cron, console. Вот так они заданы в конфиге:
/**
 * Конфигурация инстансов логгера
 */
$config['sys']['logs']['instances']=array(
	/**
	 * Стандартный поток логов
	 */
	'default'=>array(
		'handlers'=>array(
			'Stream'=>array(
				'___path.application.server___/logs/___sys.logs.file___',
				'debug',
				'formatter'=>array(
					'Line','___sys.logs.format___'
				)
			),
		),
		'processors'=>array(
			'Uid','ProcessId',
		)
	),
	/**
	 * Логи запросов к БД
	 */
	'db_query'=>array(
		'handlers'=>array(
			'Stream'=>array(
				'___path.application.server___/logs/___sys.logs.sql_query_file___',
				'debug',
				'formatter'=>array(
					'Line','___sys.logs.format___',null,true
				)
			),
		),
		'processors'=>array(
			'Uid','ProcessId',
		)
	),
	/**
	 * Логи ошибок к БД
	 */
	'db_error'=>array(
		'handlers'=>array(
			'Stream'=>array(
				'___path.application.server___/logs/___sys.logs.sql_error_file___',
				'debug',
				'formatter'=>array(
					'Line','___sys.logs.format___',null,true
				)
			),
		),
		'processors'=>array(
			'Uid','ProcessId',
		)
	),
	/**
	 * Логи cron скриптов
	 */
	'cron'=>array(
		'handlers'=>array(
			'Stream'=>array(
				'___path.application.server___/logs/___sys.logs.file___',
				'debug',
				'formatter'=>array(
					'Line','___sys.logs.format___'
				)
			),
		),
		'processors'=>array(
			'Uid','ProcessId',
		)
	),
	/**
	 * Вывод собщений в консоле браузера
	 */
	'console'=>array(
		'handlers'=>array(
			'BrowserConsole'=>array(),
		),
	),
);

Для каждого потока можно задать список хендлеров (handlers, метод обработки и хранения логов) со своим форматированием и дополнительные обработчики (processors). Подробнее о handlers, formatter и processors можно прочитать в доке к Monolog — github.com/Seldaek/monolog/blob/master/README.mdown
Модуль предоставляет 7 уровней логирования: debug, info, notice, warning, error, critical, alert, emergency. Запись в лог идет через одноименные методы, например:
$this->Logger_Debug('hello!');
$this->Logger_Error('bug!',array('param1'=>111,'param2'=>22),'mychannel');

Описание методов выглядит так:
	 /**
	 * Логирует с уровнем Debug
	 *
	 * @param string  $sMsg	Сообщение
	 * @param array  $aContext	Дополнительные параметры для логирования
	 * @param string $sInstance	Имя инстанса
	 */
	public function Debug($sMsg,$aContext=array(),$sInstance='default') {
		...
	}

Отдельно стоит упомянуть о инстансе console. Он позволяет выводить сообщения лога прямо в консоль браузера, например, в FireBug. Для его удобного использования есть специальный метод $this->Logger_Console($param1,$param2,...); и функция обертка dump(). Но нужно помнить, что метод работает только при настройке конфига sys.logs.console=true.

Перехват всех PHP ошибок
Еще одна новая возможность — это перехват и запись в лог всех возникающих PHP ошибок, в том числе и фатальных. Теперь вы всегда будете в курсе проблем вашего сайта. За этот функционал отвечает параметр конфига sys.logs.php=true

5 комментариев

avatar
Планируется ли среди типов бэкэндов Варниш?
avatar
Я не работал с ним, но это вроде как кеширующий прокси, а не key-value хранилище
avatar
Да, верно. Задал вопрос, не дочитав статью до конца.

Варниш позволяет кэшировать отдельные блоки html-документов. Есть ли какие-то планы в этом направлении? Как известно, штатный кэш не отличается производительностью.
avatar
Как известно, штатный кэш не отличается производительностью.
Включенный по-умолчанию файловый кеш — да. Он больше вредит чем приносит пользы.
avatar
Хочу только сказать что Monolog поддерживает разные ресурсы вывода, т.е. вывод некоторых ошибок можно настроить так, что уведомления о них будут приходить на почту, минуя основной (нужные) логи.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.