FrontTalks: Алексей Андросов (Яндекс), «Ошибки, которые мы...

Post on 22-May-2015

841 views 0 download

description

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

Transcript of FrontTalks: Алексей Андросов (Яндекс), «Ошибки, которые мы...

Ошибки, которые мылюбим

Алексей Андросов

Старший разработчик интерфейсов

FrontTalks, Екатеринюург, 5 июля 2013 года

www.princexml.com
Prince - Non-commercial License
This document was created with Prince, a great way of getting web content onto paper.

Обо мнеdoochik@ya.ru @doochik

● По образованию – специалист по защите

информации

● 6 лет в Яндексе, 2 года ведущий разработчик

фронтенда в Я.Почте

● Люблю копаться в браузерах и внедрять новые фичи из HTML5

● Можете спрашивать про JS, CSS и frontend в целом

02

Баги – это нормально

Баги – это нормально● Браузер – неконтроллируемая среда для исполнения вашего кода.

04

Баги – это нормально● Браузер – неконтроллируемая среда для исполнения вашего кода.

● Дефграгменация рынка браузеров.

05

Баги – это нормально● Браузер – неконтроллируемая среда для исполнения вашего кода.

● Дефграгменация рынка браузеров.

● Человеку свойственно ошибаться.

Если вы меряете эффективность своей работы по количеству

багов, поздравляю, у вас серьёзные проблемы.

06

Первое правило:вы — дурак,а все вокруг —Д'Артаньяны

Второе правило:ошибка не в вашемкоде, а в коде вашейкоманды

Релизный цикл

[Object]

[Object]

[Object]

[Object]09

Релизный цикл

[Object]

[Object]

[Object]

[Object]

[Object]10

Релизный цикл + мониторинг

[Object]

[Object]

[Object]

[Object]

[Object]11

Зачем мониторинг?● Сломаться может в любой момент

12

Зачем мониторинг?● Сломаться может в любой момент

● Никто не гарантирует, что релиз заработает у реальных

пользователей

13

Зачем мониторинг?● Сломаться может в любой момент

● Никто не гарантирует, что релиз заработает у реальных

пользователей

● Превысили допустимый предел ошибок – послали уведомление

14

Зачем мониторинг?● Сломаться может в любой момент

● Никто не гарантирует, что релиз заработает у реальных

пользователей

● Превысили допустимый предел ошибок – послали уведомление

● Можно строить статистику

15

На что смотрим● Доступность сервиса (код HTTP-ответа = 200)

16

На что смотрим● Доступность сервиса (код HTTP-ответа = 200)

● Скорость отдачи страниц

17

На что смотрим● Доступность сервиса (код HTTP-ответа = 200)

● Скорость отдачи страниц

● Количество совершенных действий

18

На что смотрим● Доступность сервиса (код HTTP-ответа = 200)

● Скорость отдачи страниц

● Количество совершенных действий

● Количество писем в службу поддержки

● и т.п.

19

А причем здесьфронтенд?

Что можно отследить вбраузере

● onload

● ondomcontentload

● Инициализация JS-компонентов

● JS-ошибки

● и т.п.

21

А еще можно считать...● скорость загрузки

● скорость инициализации

● время ответа бекенда

● и т.п.

22

Почему именно в браузере● Эти события нельзя отследить по-другому

23

Почему именно в браузере● Эти события нельзя отследить по-другому

● Если сервер ответил на HTTP-запрос, это не значит, что браузер

его принял

24

Пример (запуск сервиса)$(projectNS.init);

25

Пример (запуск сервиса)if (window['jQuery']) {

$(projectNS.init);

} else {

log({type: 'fatal', error: 'no-jquery'});

}

26

Пример (запуск сервиса)if (window['jQuery']) {

if (window['projectNS']) {

$(projectNS.init);

} else {

log({type: 'fatal', error: 'no-project-js'});

}

} else {

log({type: 'fatal', error: 'no-jquery'});

}

27

Одна функция на все времена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

window.onerror● Обработчик всех JS-ошибок в браузере

● Есть errorMessage, scriptUrl, line

● Нет стека вызовов

29

window.onerrorwindow.onerror = function(msg, url, line) {

log({

type: 'jserror',

msg: msg,

url: url,

line: line

})

})

30

Но......первые логи вам выдадут вот такую статистику

95% msg=Script error.&url=&line=0

0.2% ...

0.1% ...

01.

02.

03.

31

Главная проблемаwindow.onerrorIf 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

Главная проблемаwindow.onerrorРешается только в Firefox 13+ с помощью

<script src="…" crossorigin="anonymous" ></script>.

А сервер должен ответить CORS-заголовком

Access-Control-Allow-Origin: *

Атрибут есть в черновике HTML 5.1. Ждем…

33

Главная проблемаcrossorigin="anonymous"Если Chrome, Firefox или Opera не получит правильный заголовок

Access-Control-Allow-Origin , то заблокирует загрузку

скрипта.

34

try-catch?Все обернуть в try-catch сложно, потому что JS – асинхронный

язык.

Также стоит учитывать, что try-catch влияет на

производительность.

35

Другие способыисполнения JS

Общий принцип1. Грузим JS как текст (XHR, localStorage)

2. Исполняем в браузере в same-origin policy

38

createElement('script')onerror

msgonerror

urlonerror

linecatchmsg

catchurl

catchline

Chrome 26 + - - + - *

Fx 22 + - - + - *

IE 9 + - - + - -

IE 10 + - - + - *

Opera 12.15 + - - + - *

* – строка без урла почти бесполезна

39

eval / new Function / setTimeoutonerror

msgonerror

urlonerror

linecatchmsg

catchurl

catchline

Chrome 26 + - * + - *

Fx 22 + - - + - -

IE 9 + - - + - -

IE 10 + - * + - *

Opera 12.15 + - * + - *

* – строка без урла почти бесполезна

40

<script src="data:..."onerror

msgonerror

urlonerror

linecatchmsg

catchurl

catchline

Chrome 26 - - - + * **

Fx 22 - * - + * -

Opera 12.15 - - - + * **

<script src="data:text/javascript,...">

* – урлом является весь src (исходный текст)

** – код вытягивается в одну строку

41

<a href="javascript:..."onerror

msgonerror

urlonerror

linecatchmsg

catchurl

catchline

Chrome 26 + - - + - **

Fx 22 + * - + * -

IE 9 + - - + - -

IE 10 + - ** + - **

Opera 12.15 - - - + * **

* – урлом является весь src (исходный текст)** – код вытягивается в одну строку42

Blobvar blob = new Blob([code],

{type: 'text/javascript'});

var url = URL.createObjectURL(blob);

var script = document.createElement('script');

script.src = url;

URL.revokeObjectURL(url);

document.body.appendChild(script);

43

Blobonerror

msgonerror

urlonerror

linecatchmsg

catchurl

catchline

Chrome 26 + * + + * +

Fx 22 + * + + * +

IE 10 + * + + * +

* – урлом является id Blob'а. Если исполняется несколько кусков

кода, то можно сделать простой маппинг ресурсов

44

Что еще надо знатьпро window.onerror?

Избавляемся от вечного"error at line 1"После минификации весь код вытягивается в одну строку, из-за

этого неудобно искать ошибки с символе 30768.

Поможет UglifyJS

$ uglifyjs page.js -b beautify=false,max-line-len=100

46

Вместо msg может бытьсобытие...о незагрузке скрипта

if (msg && typeof msg != 'string') {

if (msg.type && msg.target) {

try {

url = msg.target.src;

} catch(e) {}

msg = 'Error loading script';

}

}47

Фильтруем не наши ошибкиif (url && (

/(miscellaneous|extension)_bindings/.test(url) ||

/^chrome:/.test(url) ||

/^file:/.test(url)

) {

return;

}

48

Обрабатываем JSONPif (url && /(&|\?)callback=/.test(url)) {

errorType = 'noJSONPResponse';

}

49

Что ещё можнологировать?

Неожиданное поведениеif (data && data.status === 'OK') {

// все хорошо

} else {

log({

'type': 'something_went_wrong',

'some_usefull_data': data

)}

}

51

Важный код в try-catchtry {

// все хорошо

} сatch (e) {

log({

'type': 'exception',

'msg': e.message || e.toString(),

'stack': e.stacktrace || e.stack

)}

}

52

Транспорты и долговисящиесоединенияИх можно отлаживать с помощью скрытой консоли, доступной по

хоткею.

● Всегда можно посмотреть все события

● Можно отправлять весь лог на анализ

53

Логи для ленивых и богатых● Errorception (платный)

● ExceptionHub (платный)

● JSLogger (платный)

● Muscula (пока бесплатный)

● Proxino (платный)

● Qbaka (платный)

54

Подводим итоги

Логируем поведениепользователя

● Всегда знаете как релиз работает у настоящих пользователей.

56

Логируем поведениепользователя

● Всегда знаете как релиз работает у настоящих пользователей.

● Всегда знаете что не работает у пользователя.

57

Логируем поведениепользователя

● Всегда знаете как релиз работает у настоящих пользователей.

● Всегда знаете что не работает у пользователя.

● Проще анализировать проблему, проще службе поддержки, проще

исправить.

58

Логируем поведениепользователя

● Всегда знаете как релиз работает у настоящих пользователей.

● Всегда знаете что не работает у пользователя.

● Проще анализировать проблему, проще службе поддержки, проще

исправить.

● Резко возрос рейт ошибок? Всем разослали смс-ку и начинаем

чинить.

59

И помните1. Если в каждом релизе количество ошибок вырастает на 1%, то

через 10 релизов будет +11%

60

И помните1. Если в каждом релизе количество ошибок вырастает на 1%, то

через 10 релизов будет +11%.

2. Логов много не бывает!

61

Алексей Андросов

Старший разработчик интерфейсов

doochik@ya.ru

@doochik

github.com/doochik