Pull to refresh

Начала отладки и профилирования веб-приложений

Reading time8 min
Views18K

Вступление


Много существует статей на Хабре, описывающих интересные и сложные аспекты веб-разработки, но много существует читателей, которые, находясь в начале своей карьеры веб-разработчика, хотели бы видеть материал, который позволил бы сделать первый шаг от «PHP за 24 часа» до разработки на серьезном уровне, и я хотел бы поделиться своим опытом в этом деле.

Особенности веб-приложения делают его разделенным на две части: клиентскую и серверную. На стороне клиента работает код на JavaScript (может быть, где-то можно найти и VBScript, но мы, пожалуй, не будем рассматривать этот случай), на серверной же — много что, в принципе, но мы рассмотрим PHP, наиболее популярный язык для серверной части веб-приложений. Так же интересно было бы поговорить об отладке и профилировании Flash-приложений на клиентской стороне, но затронутая тема и так обширна, так что пока оставим это.

Так же можно отнести к задачам отладки клиентского кода анализ и валидацию HTML кода. Это, вроде бы, задача не совсем из области программирования, но также немаловажная.

Некоторые части рассмотренных задач уже рассматривались в других статьях, и я предоставил на них ссылки.

Отладка и профилирование клиентского кода


«Классическим» способом отладки кода на JavaScript является использование функции alert и ее производные. Помнится, в начале своей карьеры лично я написал функцию print_r для JavaScript, так как не видел возможности для вывода отладочной информации по массивам и объектам. Выглядело это примерно так:
function print_r(variable)
{
    if (variable instanceof Array || variable instanceof Object) {
        var key;
        for (key in variable)
            alert(key + ' => ' + variable[key]);
    }
    else {
        alert(variable);
    }
}


О каком-либо профилировании речи, конечно, не велось совсем.

При таком подходе даже информация об объекте console производит революцию.

Специфика клиентской стороны веб-приложения требует отладки кода во всех популярных браузерах. Конечно, чаще всего хватает и отладки в Internet Explorer'е и любом нормальном другом браузере, но мы рассмотрим все варианты.

Mozilla Firefox

Наверно, именно Firefox можно назвать пионером отладки клиентского кода. Долгое время его указывали как браузер, наиболее подходящий для разработки, а все благодаря расширению Firebug, которое содержит, наверно, все нужные возможности, кроме валидации HTML кода.



Так же, начиная с версии 4, появилась встроенная Веб-консоль, которая реализует часть функций вкладки «Консоль» и «Сеть» Firebug'а, а так же некоторые возможности по отладке CSS.



Начиная с версии 6, появился Простой редактор JavaScript, который так же реализует одну из функций Firebug'а, и позволяет писать и выполнять код прямо в браузере.



Начиная с версии 10 появился Инспектор страниц, который позволяет изучать HTML код и CSS свойства, то есть, реализует функции вкладки «HTML».



За валидацию HTML кода как правило отвечает расширение Html Validator. Как раз его иконку, указывающую на количество ошибок на главной странице сайта habrahabr.ru, можно видеть в правом нижнем углу браузера на картинке с Инспектором страниц.

Так же, пользуясь случаем, укажу, что для этого браузера есть множество расширений, позволяющих облегчить жизнь, о чем на Хабре уже была соответствующая статья.

Google Chrome и Safari

Эти браузеры, основанные на WebKit, обладают встроенным инструментом разработки Web Inspector, который очень хорошо развит и реализует практически те же функции, что и Firebug. При этом, надо отдать ему должное, он не замедляет работы браузера, что водится за «старшим братом».



В Chrome он может быть вызван по нажатию клавиш Ctrl+Shift+I или просто по F12. В Safari он хорошо спрятан, и для его использования нужно включить возможности разработки в настройках браузера. Позже инструменты разработчика станут доступными из пункта «Разработка» главного меню или по сочетанию клавиш Ctrl+Alt+I.

Для валидации HTML кода так же нужно устанавливать сторонние расширения. К примеру, для Chrome, это может быть Validity. Для Safari пока не удалось подобрать ничего подходящего.

Opera

Opera так же имеет встроенный инструмент для разработчиков, который называется «Opera Dragonfly», и может быть вызван в любой момент по сочетанию клавиш Ctrl+Shift+I. Он похож на то, что нам представляет WebKit, и имеет подобные возможности и плюсы, хотя, на мой лично взгляд, менее удобен.



Как подсказал товарищ homm, в Опере есть простое средство отправить страницу на валидацию в validator.w3.org. В контекстном меню области отображения сайта есть пункт «Соблюдены ли веб-стандарты», который как раз и отвечает за это.

С расширениями для валидации HTML в каталоге Оперы напряженная ситуация. По этой причине у расширения Validator нет альтернатив.

Internet Explorer

Начиная с версии 8 и здесь появился инструментарий разработчика. Он предоставляет примерно те же возможности, что и в случаях остальных браузеров, но, как и в других аспектах своей деятельности, Internet Explorer предоставляет их с некоторыми особенностями и непередаваемым изяществом. Важным пунктом является возможность эмуляции более старых версий, а так же режима совместимости.



Принято считать, что в версиях 7-, над которыми пролились моря слез верстальщиков и JS-программистов, подобных инструментов нет. Существует стороннее решение, Companion.JS, о котором была соответствующая статья. Конечно, его возможности значительно уступают привычным инструментам, но это средство хотя бы позволяет отлаживать код более продвинуто, чем «alert-ориентированная отладка».

Товарищ atd подсказал, что и для этих многострадальных версий «родной» инструментарий под названием «Internet Explorer Developer Toolbar» был, но требовал отдельной установки: www.microsoft.com/download/en/details.aspx?id=18359

Так же товарищ k12th напомнил, что при наличии Visual Studio можно отлаживать код в ней (компоненты «Web Development Tools»). Так же можно найти информацию о бесплатной версии Visual Web Developer Express.

Отладка и профилирование серверного кода


Xdebug

Как мы договорились в начале, мы рассматриваем случай, когда на сервере используется PHP. Тут «классическим» методом отладки являются echo, print_r и var_dump, но есть так же и средство для отладки, как в лучших домах — Xdebug. Лично для меня, в связи со спецификой обучения в институте, это выглядело «прямо как в Delphi».

Расширение xdebug позволяет как минимум прогонять код по шагам и просматривать значения переменных, что поднимает программирование на PHP на новый уровень. О тонкостях работы с xdebug была соответствующая статья. XDebug обычно доступен в репозиториях GNU/Linux, в Windows его так же не слишком сложно установить, скопировав dll файл.

При использовании этого расширения, с сервера на компьютер разработчика поступает входящее соединение (по умолчанию на порт 9000), которое он должен обработать. Для этого необходимо соответствующим образом настроить свою IDE.

Кстати говоря, использование IDE так же является непременным условием движения вперед. Некоторые программисты считают, что разницу между программированием в блокноте с подсветкой кода и в IDE можно увидеть только на крупных проектах, но лично я придерживаюсь мнения, что разница видна даже на программе «Hello world!» — одна автоподстановка имен и аргументов стандартных функций чего стоит.

XHProf

О расширении

Да, xdebug предоставляет возможности по профилированию, но разработка Facebook'а для этих целей, XHProf, лично мне больше нравится. Я, сказать честно, не проводил никаких тестов, но считается, что данное расширение гораздо лучше подходит для production-серверов и для профилирования при реальных нагрузках.

Установка

К сожалению, это расширение не входит ни в какие репозитории. Оно входит в PECL, но по какой-то причине его установка штатным путем часто вызывает проблемы. По этой причине приходится проводить установку из исходников.

# Получаем исходники
wget http://pecl.php.net/get/xhprof-0.9.2.tgz
# Распаковываем исходники
tar -xvf xhprof-0.9.2.tgz
# Переходим в каталог, где содержится код расширения
cd xhprof-0.9.2/extension/
# Проводим компиляцию и тест
phpize
./configure
make
make test
# Проводим установку цивилизованно
checkinstall

Файл конфигурации xhprof.ini предоставляет нам примерно такие возможности:

[xhprof]
extension=/usr/local/lib/php/extensions/no-debug-non-zts-20090626/xhprof.so
; Каталог для логов
xhprof.output_dir="/var/log/xhprof/"


Профилирование

Каталог, который мы получаем, распаковав архив, содержит помимо исходников расширения так же и веб-интерфейс для изучения результатов профилирования, и библиотеки для профилирования приложения.

Приведем пример профилирования. В код приложения нужно включить следующие элементы:
// Начало скрипта, включаем профилирование
// как нагрузки на процессор, так и на память
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

/*
* Основной код приложения
*/

// Конец скрипта, завершаем профилирование,
// записываем результат в лог
$xhprofData = xhprof_disable();
include_once XHPROF_DIR.'/xhprof_lib/utils/xhprof_lib.php';
include_once XHPROF_DIR.'/xhprof_lib/utils/xhprof_runs.php';
$xhprofRuns = new XHProfRuns_Default();
$namespace = 'some-unique-name';
$runId = $xhprofRuns->save_run($xhprofData, $namespace);
echo "<!-- ", $runId, ' ', $namespace, " -->\n";

Здесь константа XHPROF_DIR указывает на каталог, куда мы распаковали скачанный архив.

Для анализа результатов нужен тот самый веб-интерфейс. Его можно взять в каталоге $XHPROF_DIR/xhprof_html/ — условно обозначим его так. К примеру, мы расположили его в доступном веб-серверу месте, и он доступен по адресу example.com/system/xhprof/, тогда для анализа результата работы нам нужно обратиться к нему следующим образом:

example.com/system/xhprof/?run=%runId%&source=%namespace%

Мы получим подобный результат:


Профилирование можно включать в код приложения на постоянной основе или, например, сделать так, чтобы оно запускалось случайно с определенной вероятностью или по наличию определенного условия. Например, так:

$needProfiler = (mt_rand(0, 100) < 10 or isset($_COOKIE['xhprof']));
if ($needProfiler)
    xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

В таком случае можно, имея жалобы от клиентов или подозрения, обратиться к результатам профилирования за определенный временной промежуток. С помощью параметра namespace можно определить, какая именно часть приложения (какой скрипт, контроллер, экшн) профилировались.

Профилирование SQL запросов

Как правило, именно работа с базой данных является узким местом в приложении. По этой причине рекомендуется проводить профилирование запросов. К примеру, рассмотрим часть класса, являющегося оберткой вокруг функций расширения mysql. Да, я знаю, что это расширение не очень любят и желают ему смерти не меньше, чем старому-доброму IE6. Я не призываю его использовать, просто именно такой класс есть у меня под рукой.

/**
 * Запрос
 * @param string $sql Запрос
 * @param array $params Параметры
 * @param string $query Скомпилированный запрос
 * @return array Результат
 */
public function query($sql, array $params = array(), &$query = '')
{
    $start = microtime(TRUE);

    // Проведение запроса, включая "защиту" параметров

    $stop = microtime(TRUE);
    $time = $stop - $start;
    $this->_addProfilerData($sql, $time);

    // Возврат результата
}

private function _addProfilerData($query, $time)
{
    if (is_array(self::$profilerData)) {
        self::$profilerData[] = array(
            'query' => $query,
            'time' => $time
        );
    }
}

public function __destruct()
{
    if (is_array(self::$profilerData)) {
        $this->_writeProfilerData();
        self::$profilerData = FALSE;
    }

    // Отключение от БД
}

private function _writeProfilerData()
{
    $values = array();
    foreach (self::$profilerData as $row) {
        $query = mysql_real_escape_string($row['query'], $this->con);
        $time = (float)$row['time'];
        $hash = crc32($row['query']);
        $values[] = "($hash, '$query', $time)";
    }

    if ($values) {
        $strValues = implode(', ', $values);
        $sql = "INSERT DELAYED INTO `profiler_queries` (`query_hash`, `query`, `work_time`) VALUES $strValues";
        @mysql_query($sql, $this->con);
    }
}

Здесь данные профилирования запросов хранятся в таблице profiler_queries. Эта таблица может иметь тип MyISAM или Archive, так как они предоставляют возможность совершать отложенные вставки, что не создает излишней задержки ответа при профилировании. Так же для лучшего поиска запросов в таблице лучше создать столбец типа INT, куда будет писаться crc32-хеш запроса, по которому нужно создать индекс.

Заключение


Статья получилась достаточно большой. Возможно, здесь я прошелся по верхам и затронул темы, которые уже затрагивались, но если бы я в свое время прочитал что-то подобное — статью, где вся информация собрана вместе и даны полезные ссылки, это оказало бы мне неоценимую помощь. Я надеюсь, что и моя статья поможет кому-нибудь на пути к просветлению.

Ссылки


  1. Используем console на полную
  2. Firebug: Part 1 — console
  3. Расширения Firefox для веб-разработки на все случаи жизни
  4. JavaScript debugger для IE
  5. Debugging PHP applications with xdebug
  6. Профилирование PHP-кода
  7. Pinba — мониторим php в реальном времени (подсказал trueneutral)
  8. Webgrind — Xdebug profiling web frontend (подсказал truezemez)
  9. Internet Explorer Developer Toolbar
  10. XDEBUG EXTENSION FOR PHP
  11. XHProf (GitHub)
Tags:
Hubs:
+22
Comments26

Articles