javascript

Отслеживание js-ошибок с помощью Метрики

  • четверг, 23 марта 2017 г. в 03:13:53
https://habrahabr.ru/post/324366/
  • JavaScript


Использование системы отслеживания js-ошибок трудно переоценить. Даже на покрытом тестами сайте возникают js-ошибки, важно их найти и починить. Расскажу как искал подходящее решение.


Существует три вида систем отслеживания js-ошибок.


Первый вид


Самописная система. Добавляем компактный js-код на сайт:


window.onerror = function(msg, file, line, col) {
    new Image().src = '/jserrors/?msg=' + msg + ...;
}

Делаем «ручку» для сохранения ошибок, парсим логи. В лучшем случае, пишем свой интерфейс для анализа ошибок. Потом занимаемся доработкой и поддержкой.


Второй вид


Платный сервис с расширенными возможностями, но с ограничениями, например, на количество js-ошибок в день или месяц. На любой сайт поставить эту систему не получится, придётся каждый раз выбирать какой из ваших сайтов «достоин» платного сервиса. И не забывать оплачивать услуги.


Нужно будет добавить на сайт внешний скрипт, который отрицательно повлияет на скорость загрузки вашего сайта.


Третий вид


Использовать для сбора ошибок систему аналитики, для этого необходимо установить на сайт её полноценный код отслеживания.


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


Решение


Объединим первый и третий вид. Ошибки будем вручную отправлять в Яндекс.Метрику с помощью компактного js-кода. В Метрике есть необходимые отчёты и инструменты для анализа данных, нет особых ограничений на количество счётчиков и собираемых данных, и она бесплатна.


Для сбора ошибок подойдёт отчёт «Параметры визитов».


  1. Заведём отдельный счётчик.


  2. Добавим на страницу перед всеми скриптами компактный код:


    <script>
    // Не более 320 байт после минификации.
    window.onerror = function(msg, file, line, col, err) {
        // Отсекаем совсем старые браузеры.
        if (!window.JSON) { return; }
    
        var counterId = 12345, // Ваш номер счётчика Метрики.
            siteInfo = {},
            pointer = siteInfo;
            // Список параметров визитов.
            path = [
                'JS errors', // 1 уровень
                msg, // 2 уровень
                err && err.stack || (file + ':' + line + ':' + col) // 3 уровень
                // Не хватает параметров? Добавьте ещё!
            ];
    
        // Преобразуем параметры из плоского в древовидный вид для отчёта.
        for (var i = 0; i < path.length - 1; i++) {
            var item = path[i];
            pointer[item] = {};
            pointer = pointer[item];
        }
    
        pointer[path[i]] = 1;
    
        new Image().src = 'https://mc.yandex.ru/watch/' + counterId +
            '/?site-info=' + encodeURIComponent(JSON.stringify(siteInfo))
            '&rn=' + Math.random();
    };
    </script>

  3. Не забываем указать в коде свой номер счётчика (counterId).


  4. Получаем примерно такой отчёт:


Структуру и порядок параметров в отчёте можно менять на лету, а также добавлять новые параметры. Давайте с помощью кнопки «Группировки» добавим браузер и ОС в отчёт.



И ещё один момент, если скрипты на сайте загружаются с другого домена (CDN), то в отчёте, скорее всего, будут видны сообщения вида «Script error» и без стека.
Чтобы вернуть сообщениям нормальный вид, необходимо добавить к скриптам атрибут crossorigin="anonymous" и HTTP-заголовок Access-Control-Allow-Origin:"*".


<script src="https://mycdn.com/folder/file.js" crossorigin="anonymous"></script>

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


Дополнительно добавим ограничение на собираемое количество ошибок (не более 5) на странице. Например, однотипные ошибки, возникающие при движении мышки, могут создать сотни запросов в Метрику.


В современных браузерах данные будем отправлять через sendBeacon.


<script>
window.onerror = function handler(msg, file, line, col, err) {
    if (!window.JSON || handler.count > 5) { return; }

    var counterId = 12345, // Ваш номер счётчика Метрики.
        siteInfo = {},
        pointer = siteInfo,
        stack = err && err.stack,
        path = [
            // Укажите в регулярном выражении домены, с которых загружаются ваши скрипты и сайт.
            'JS ' + (!file || /mysite\.ru|cdn\.com/.test(file) ? 'in' : 'ex') + 'ternal errors',
            'message: ' + msg,
            stack ?
                'stack: ' + stack :
                (file ? 'file: ' + file + ':' + line + ':' + col : 'nofile'),
            'href: ' + location.href
        ];

    for (var i = 0; i < path.length - 1; i++) {
        var item = path[i];
        pointer[item] = {};
        pointer = pointer[item];
    }

    pointer[path[i]] = 1;

    var url = 'https://mc.yandex.ru/watch/' + counterId + '/' +
            '?site-info=' + encodeURIComponent(JSON.stringify(siteInfo)) +
            '&rn=' + Math.random();

    if (typeof navigator.sendBeacon === 'function') {
        navigator.sendBeacon(url, ' ');
    } else {
        new Image().src = url;
    }

    if (handler.count) {
        handler.count++;
    } else {
        handler.count = 1;
    }
};
</script>

И ещё, данные по ошибкам можно получить с помощью API и сделать с ними всё что угодно.


Не забудьте добавить ссылки на отчёты по ошибкам в свою документацию на видное место.
И дать доступ к отчётам остальным разработчикам из группы, чтобы исправление ошибок превратилось в соревнование.


Ссылки: