Мониторинг – важная часть работы хорошего сервиса. Мало просто протестировать релиз, надо также убедиться, что код работает у пользователей и работает правильно. В докладе я расскажу про логирование js-ошибок при разных способах загрузки js, подводных камнях, способах их обойти, а также почему это надо делать.
2. Обо мне
doochik@ya.ru @doochik
● По образованию – специалист по защите
информации
● 6 лет в Яндексе, 2 года ведущий разработчик
фронтенда в Я.Почте
● Люблю копаться в браузерах и внедрять новые фичи из HTML5
● Можете спрашивать про JS, CSS и frontend в целом
02
4. Баги – это нормально
● Браузер – неконтроллируемая среда для исполнения вашего кода.
04
5. Баги – это нормально
● Браузер – неконтроллируемая среда для исполнения вашего кода.
● Дефграгменация рынка браузеров.
05
6. Баги – это нормально
● Браузер – неконтроллируемая среда для исполнения вашего кода.
● Дефграгменация рынка браузеров.
● Человеку свойственно ошибаться.
Если вы меряете эффективность своей работы по количеству
багов, поздравляю, у вас серьёзные проблемы.
06
13. Зачем мониторинг?
● Сломаться может в любой момент
● Никто не гарантирует, что релиз заработает у реальных
пользователей
13
14. Зачем мониторинг?
● Сломаться может в любой момент
● Никто не гарантирует, что релиз заработает у реальных
пользователей
● Превысили допустимый предел ошибок – послали уведомление
14
15. Зачем мониторинг?
● Сломаться может в любой момент
● Никто не гарантирует, что релиз заработает у реальных
пользователей
● Превысили допустимый предел ошибок – послали уведомление
● Можно строить статистику
15
17. На что смотрим
● Доступность сервиса (код HTTP-ответа = 200)
● Скорость отдачи страниц
17
18. На что смотрим
● Доступность сервиса (код HTTP-ответа = 200)
● Скорость отдачи страниц
● Количество совершенных действий
18
19. На что смотрим
● Доступность сервиса (код HTTP-ответа = 200)
● Скорость отдачи страниц
● Количество совершенных действий
● Количество писем в службу поддержки
● и т.п.
19
26. Пример (запуск сервиса)
if (window['jQuery']) {
$(projectNS.init);
} else {
log({type: 'fatal', error: 'no-jquery'});
}
26
27. Пример (запуск сервиса)
if (window['jQuery']) {
if (window['projectNS']) {
$(projectNS.init);
} else {
log({type: 'fatal', error: 'no-project-js'});
}
} else {
log({type: 'fatal', error: 'no-jquery'});
}
27
28. Одна функция на все времена
function log(data) {
var props = [];
for (var key in data) {
var value = encodeURIComponent(data[key]);
var key = encodeURIComponent(key);
props.push(key + '=' + value);
}
new Image().src = '/log?' + props.join('&');
}
28
31. Но...
...первые логи вам выдадут вот такую статистику
95% msg=Script error.&url=&line=0
0.2% ...
0.1% ...
01.
02.
03.
31
32. Главная проблема
window.onerror
If the location URL does not have a same origin as the origin, then set
message to "Script error.", set location to the empty string, and set line
to 0.
http://dev.w3.org/html5/spec/webappapis.html#report-the-error
“
32
33. Главная проблема
window.onerror
Решается только в Firefox 13+ с помощью
<script src="…" crossorigin="anonymous" ></script>.
А сервер должен ответить CORS-заголовком
Access-Control-Allow-Origin: *
Атрибут есть в черновике HTML 5.1. Ждем…
33
35. try-catch?
Все обернуть в try-catch сложно, потому что JS – асинхронный
язык.
Также стоит учитывать, что try-catch влияет на
производительность.
35
46. Избавляемся от вечного
"error at line 1"
После минификации весь код вытягивается в одну строку, из-за
этого неудобно искать ошибки с символе 30768.
Поможет UglifyJS
$ uglifyjs page.js -b beautify=false,max-line-len=100
46
47. Вместо msg может быть
событие
...о незагрузке скрипта
if (msg && typeof msg != 'string') {
if (msg.type && msg.target) {
try {
url = msg.target.src;
} catch(e) {}
msg = 'Error loading script';
}
}
47
48. Фильтруем не наши ошибки
if (url && (
/(miscellaneous|extension)_bindings/.test(url) ||
/^chrome:/.test(url) ||
/^file:/.test(url)
) {
return;
}
48
51. Неожиданное поведение
if (data && data.status === 'OK') {
// все хорошо
} else {
log({
'type': 'something_went_wrong',
'some_usefull_data': data
)}
}
51
52. Важный код в try-catch
try {
// все хорошо
} сatch (e) {
log({
'type': 'exception',
'msg': e.message || e.toString(),
'stack': e.stacktrace || e.stack
)}
}
52
53. Транспорты и долговисящие
соединения
Их можно отлаживать с помощью скрытой консоли, доступной по
хоткею.
● Всегда можно посмотреть все события
● Можно отправлять весь лог на анализ
53
58. Логируем поведение
пользователя
● Всегда знаете как релиз работает у настоящих пользователей.
● Всегда знаете что не работает у пользователя.
● Проще анализировать проблему, проще службе поддержки, проще
исправить.
58
59. Логируем поведение
пользователя
● Всегда знаете как релиз работает у настоящих пользователей.
● Всегда знаете что не работает у пользователя.
● Проще анализировать проблему, проще службе поддержки, проще
исправить.
● Резко возрос рейт ошибок? Всем разослали смс-ку и начинаем
чинить.
59
60. И помните
1. Если в каждом релизе количество ошибок вырастает на 1%, то
через 10 релизов будет +11%
60
61. И помните
1. Если в каждом релизе количество ошибок вырастает на 1%, то
через 10 релизов будет +11%.
2. Логов много не бывает!
61