Sentry-javascript: Предложение узла: записывать ошибки в `unhandledRejection`

Созданный на 19 февр. 2019  ·  41Комментарии  ·  Источник: getsentry/sentry-javascript

Пакет + Версия

  • [] @sentry/browser
  • [x] @sentry/node
  • [] raven-js
  • [] raven-node _ (ворон вместо узла) _
  • [ ] Другие:

Версия:

4.6.1

Описание

По умолчанию Node регистрирует необработанные отклонения обещаний. Однако после инициализации Sentry эти журналы исчезнут. Это происходит потому, что Node не регистрирует отклонения, если существует обработчик unhandledRejection , а Sentry регистрирует такой обработчик.

Я хотел бы предложить, чтобы Sentry добавил журналирование в свой обработчик, чтобы обеспечить паритет с возможностями, предоставляемыми из коробки. По крайней мере, в документации следует упомянуть об этом поведении и необходимости вручную добавить дополнительный обработчик для восстановления ведения журнала.

Самый полезный комментарий

Мне все еще кажется странным, что uncaughtException и unhandledRejection обрабатываются по-разному. Sentry восстанавливает журнал для uncaughtException почему он не делает то же самое для unhandledRejection ? Пользователи не должны помнить об использовании этого флага узла. 🤔

Все 41 Комментарий

Звучит хорошо, однако я не уверен, должно ли это быть за нашим флагом debug: true .
В конце концов, вы сознательно подключаете обработчики ошибок, которые перенаправляют поток ошибок на Sentry.

Я тоже не уверен.

Включение Sentry не приводит к отключению ведения журнала для неперехваченных исключений, поэтому, возможно, то же самое должно быть справедливо и для необработанных отклонений обещаний. (Хотя эта разница в поведении является скорее несоответствием в Node, чем в Sentry.)

Когда я включаю Sentry, я понимаю, что он сообщает о моих ошибках, но я склонен рассматривать ведение журнала консоли как отдельную вещь, особенно в dev. 🤔

Мы не изменяем поведение ведения журнала по умолчанию, а для неперехваченных исключений сам узел запускает вызов журнала.

Я думаю, что лучшим решением здесь было бы просто отметить это в документации и оставить

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at:', p, 'reason:', reason);
});

сниппет на случай, если кто-то захочет снова включить предупреждение.

Документов хватит. По крайней мере, тогда Sentry не делает ничего особенного. На самом деле проблема здесь в Node.

или неперехваченные исключения это сам узел, который запускает вызов журнала.

Если подумать, я не уверен, что это правда.

Sentry регистрирует обработчик uncaughtException который отключает поведение узла по умолчанию (журнал + выход).

Обработчик ( defaultOnFatalError ) запускает собственный вызов журнала: https://github.com/getsentry/sentry-javascript/blob/4.6.3/packages/node/src/handlers.ts#L282.

Если мы «восстанавливаем» ведение журнала для неперехваченных исключений, я считаю, что мы должны сделать то же самое для необработанных отклонений обещаний.

Можем ли мы снова открыть это? Согласно моему последнему комментарию, теперь я считаю, что Sentry должен восстановить ведение журнала для необработанных отклонений обещаний, как это делается для неперехваченных исключений.

Я обнаружил эту проблему, потому что начинал использовать Sentry и задавался вопросом, не допустил ли я ошибку в моем коде, поскольку в моем журнале было только uncaughtException а не unhandledRejection . Было бы разумно рассматривать эти два случая одинаково.

Поэтому я бы сказал: либо регистрировать оба, либо ни то, ни другое.

Я нашел лучший способ справиться с этим, чем копирование кода из ядра Node.

λ: node --unhandled-rejections=warn app.js

Также сделал это очевидным, включив на главную страницу документации https://github.com/getsentry/sentry-docs/pull/1099

Мне все еще кажется странным, что uncaughtException и unhandledRejection обрабатываются по-разному. Sentry восстанавливает журнал для uncaughtException почему он не делает то же самое для unhandledRejection ? Пользователи не должны помнить об использовании этого флага узла. 🤔

почему он не делает то же самое для unhandledRejection

Потому что один критический ( unhandledException убивает процесс), а другой информационный (таким образом, это предупреждение, а не ошибка).

Если мы изменим порядок и выдадим предупреждение по умолчанию, мы нарушим поведение интерфейса командной строки, выдав его, несмотря на то, что --unhandled-rejections установлен в none . Сейчас все работает, как и ожидалось, согласно официальной документации узла. Это изменение _ сделало бы его нестандартным.

Как только Node решит сделать так, чтобы unhandledRejection также убил процесс (что, как они говорят, теперь для 4 версий: P), мы также внесем изменения в соответствие с официальной спецификацией.

Если мы изменим порядок и выдадим предупреждение по умолчанию, мы нарушим поведение CLI.

@kamilogorek , но при запуске с node он записывает unhandledRejection в console . Поэтому я не знаю, что говорится в официальной документации по узлам, но, по крайней мере, я замечаю такое поведение.

@freeall, только если вы не прикрепляете обработчик unhandledRejection . Если вы запустите приведенный ниже код, даже без SDK, он все равно не войдет в журнал, поэтому вы должны знать, какой код вы используете.

process.on('unhandledRejection', () => `¯\_(ツ)_/¯`);

И мы очень четко заявляем здесь, что делаем это: https://docs.sentry.io/platforms/node/default-integrations/

Системные интеграции - это интеграции, включенные по умолчанию, которые объединяются в стандартную библиотеку или сам интерпретатор. Они задокументированы, поэтому вы можете видеть, что они делают, и что их можно отключить, если они вызывают проблемы.
OnUnhandledRejection
Эта интеграция присоединяет глобальные обработчики необработанных отказов.

Я просто не хочу менять поведение узла, вот и все. И поведение: «если есть слушатель, не выдавать. Если вам все еще нужно предупреждение, используйте флаг». - и это именно то, что мы делаем.

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

Если у меня есть unhandledRejection без Sentry, я вижу его в консоли.
Если у меня есть unhandledRejection с Sentry, я не вижу его в консоли.

Мне лично не нравится, что Часовой меняет поведение.

Но именно так устроен Node.js ¯_ (ツ) _ / ¯
Если вы добавите обработчик, предупреждение исчезнет. Наш SDK добавляет обработчик, потому что это единственный способ отловить необработанные ошибки, что является основной целью SDK.

Вы, конечно, правы насчет того, как устроен узел. Когда вы прикрепляете обработчик, предупреждение исчезает.
Люди просят, чтобы вы имитировали поведение узла по умолчанию и записали его в консоль. Изменение поведения - это не то, что вы ожидаете от такого инструмента, как Sentry.

В любом случае, похоже, вы настроены на такое поведение, поэтому нет смысла продолжать обсуждение. Но спасибо, что нашли время ответить :)

@freeall тоже спасибо, всегда приятно видеть обе стороны :)

Чтобы уточнить: при включении Sentry поведение unhandledException (exit + log) сохраняется, а поведение unhandledRejection (log) - нет:

| обработчик | журналов | выходов |
| - | - | - |
| unhandledException default | да | да |
| unhandledException Sentry | да | да |
| unhandledRejection default | да | нет |
| unhandledRejection Sentry | нет | нет |

Сейчас все работает, как и ожидалось, согласно официальной документации узла.

«Как и ожидалось» здесь предполагается, что пользователь понимает, что Sentry регистрирует слушателя для unhandledRejection . Это деталь реализации, о которой пользователям не стоит беспокоиться.

Но я понимаю вашу точку зрения. Sentry также должен уважать --unhandled-rejections , чего не было бы, если бы флаг был установлен на none и Sentry продолжал регистрацию.

Комментарий @freeall довольно хорошо подводит итог:

Я думаю, что пользователи Sentry ожидают, что Sentry не изменит поведение их программы.

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

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

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

Итак, рассуждение (автор @kamilogorek )

так устроен Node.js

Для меня это немного загадочно. Как это повлияет на поведение часового?

Следует ли ожидать, что пользователи узнают о:

а) внутренняя работа часовых (регистрирует обработчики событий)

б) внутренняя работа узла (добавление обработчиков приводит к исчезновению предупреждений)

А если они этого не сделают, что ж, им следует?

Конечно, вы правы, говоря «ну, пользователь должен знать, что код делает под капотом», но в действительности все выглядит иначе. И у вас есть возможность здесь повысить удобство использования часовой или нет.

Можно сказать «нас не волнует эта конкретная проблема», но рисовать это в стиле «это не ошибка, это особенность» кажется неискренним.

TL; DR: IMOH. Если вы хотите упростить использование и уменьшить проблемы для начинающих пользователей, это следует исправить.

@OliverJAsh , @freeall
Какие решения вы использовали для этой проблемы?

@schumannd Я добавил отрывок из того, как я его загружаю. И я согласен с вами, что ответ «это не ошибка, это особенность» не кажется удовлетворительным. Я боюсь, что многие программисты не поймают некоторые ошибки в своей программе, потому что Sentry их съедает. Для меня первоочередной задачей такого инструмента, как Sentry, должно быть обнаружение ошибок, а не их создание.

...
if (isUsingSentry) {
  // Log to console because Sentry overwrites standard behavior. https://github.com/getsentry/sentry-javascript/issues/1909.
  // Note that it doesn't overwrite for uncaughtException.
  process.on('unhandledRejection', console.error)
}
...

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

@OliverJAsh , @kamilogorek
Можем ли мы снова открыть и исправить это?

Sentry абсолютно не должен вмешиваться в то, как ошибки регистрируются в консоли - и это проблема не только для Node, поскольку ведение журнала консоли также подавляется в браузере.

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

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

Итак, небольшая отладка показывает причину, по которой ведение журнала консоли подавлено:

image

Sentry назначает функцию window.onunhandledrejection , и, как мы видим здесь, эта функция возвращает false , тем самым явно подавляя ведение журнала консоли. Так что да, Sentry _изменяет_ поведение по умолчанию - это не круто.

К счастью, он хранит ссылку на любую существующую функцию и вызывает ее, если она существует.
Итак, хитрый обходной путь для повторного включения ведения журнала консоли состоит в том, чтобы добавить эту строку перед инициализацией Sentry:

window.onunhandledrejection = () => true;

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

@schumannd, пожалуйста,

@ thomas-darling Я согласен с изменением браузера, он также должен возвращать true для обещаний, и я могу это изменить.

Однако насчет узла я все еще не уверен по одной причине. Он связывает код с текущей реализацией узла. Если мы скопируем внутренние компоненты вместо того, чтобы полагаться на флаги, и поведение отклонения обещаний изменится в версии 14, нам придется определить, в какой версии узла мы находимся, и действовать соответствующим образом.
Не имеет значения, что мы возвращаем от слушателя, поскольку внутренний узел просто проверяет массив слушателей и выдает предупреждение только в том случае, если слушателей вообще нет, и это обнаружение не может быть изменено - https://github.com/nodejs /node/blob/7cf6f9e964aa00772965391c23acda6d71972a9a/lib/internal/process/promises.js#L163 -L216

По поводу смены браузера: +1:

Что касается Node, если вы не исправляете вход в Sentry, вы просто заставляете всех своих пользователей делать это сами - с дополнительным риском того, что некоторые сделают это неправильно, а некоторые даже не поймут, что им это нужно, пока они не быть укушенным производственной ошибкой, как и я. Это не лучший опыт разработчика ...

@ thomas-darling, как бы вы хотели это исправить? Воспроизвести тот же код, что и внутри кода узла?

В самом верху наших документов есть очень заметное примечание, что нужно сделать, чтобы получить логирование консоли по умолчанию - https://docs.sentry.io/platforms/node/

image

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

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

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

На мой взгляд, есть несколько вариантов:

  1. Реплицируйте способ работы Node.js
  2. Просто напишите на console.error если есть необработанный отказ
  3. Подавите ошибку, чтобы разработчик никогда ее не увидел

Я думаю, что оба варианта 1 или 2 кажутся хорошими. Ваш клиент видит ошибку и может ее исправить.
Чего вам категорически не следует делать, так это варианта 3, когда ваш клиент не видит ошибок, а Sentry заставляет ошибки поступать в производственную среду (о, как ни парадоксально для инструмента отчетов об ошибках). Это текущее поведение, и это действительно должно прекратиться! Sentry должен помогать мне обнаруживать ошибки, а не делать их хуже.

Даже если вы выберете вариант 2, по крайней мере, разработчики увидят отказ и заметят, что им нужно другое поведение (например, сбой), и смогут реализовать это. Но, не зная, что был отказ, они ничего не могут с этим поделать.

Это должно сработать. https://github.com/getsentry/sentry-javascript/pull/2312
Я не добавил способ добавить ваш собственный обратный вызов, так как написание кода ниже будет иметь точно такой же эффект:

`` js
Sentry.init ({
интеграции: [
новый Sentry.Integrations.OnUnhandledRejection ({
режим: 'нет'
})
]
});

process.on ('unhandledRejection', (причина) => {
// ваш обратный вызов
})

для меня это приводит к TypeError: undefined is not a constructor . Возможно, потому что сейчас я использую пакет @sentry/react-native . Кстати, у этого пакета такая же проблема?

@schumannd @sentry/react-native не использует @sentry/node , поэтому у него нет этой интеграции. Для этого вам просто нужно обновить версию, как только мы выпустим sentry / browser, и она будет работать нормально (поскольку изменение для возврата true из обработчиков является значением по умолчанию и не настраивается).

@kamilogorek мне нравится 👍

Спасибо за это! Сможете ли вы пинговать здесь, как только это будет выпущено?

@OliverJAsh пинг :)

Просто чтобы проверить, я правильно понимаю: если я использую флаг Node --unhandled-rejections=strict , Node вызовет необработанное отклонение как исключение, а затем Sentry перехватит это исключение и сообщит о нем? Это то, что я думаю, что вижу.

Я спрашиваю, потому что, когда я пытался включить --unhandled-rejections=strict , казалось, что интеграция OnUnhandledRejections не возымела никакого эффекта - прослушиватель событий так и не был вызван.

Было бы здорово, если бы мы могли добавить несколько документов по этому поводу!

PR Документов уже идет https://github.com/getsentry/sentry-docs/pull/1351/

@OliverJAsh это изменение не имеет ничего общего с флагом cli. Его поведение осталось нетронутым. Изменилось то, что OnUnhandledRejection интеграция получила новую опцию, которая позволяет заставить ее вести себя как флаг cli.

Sentry.init({
  integrations: [
    new Sentry.Integrations.OnUnhandledRejection({
      mode: 'none'
    })
  ]
});

(концептуально) то же самое, что и --unhandled-rejection=none и то же самое касается warn и strict .
Когда вы используете warn (сейчас это значение по умолчанию), оно регистрирует само предупреждение и ошибку, но процесс будет оставаться активным.
Когда вы используете strict , он регистрирует, фиксирует событие, сбрасывает его (дождитесь его доставки) и завершает процесс с кодом выхода 1.

В этом есть смысл. Я понимаю, что интеграция не меняет поведения флага узла. Однако могу ли я просто проверить, правильно ли я понимаю, как Sentry ведет себя (вне этой интеграции) в отношении флага узла?

Просто чтобы убедиться, что я правильно понимаю: если я использую флаг Node --unhandled-rejection = strict, Node вызовет необработанное отклонение как исключение, а затем Sentry перехватит это исключение и сообщит о нем? Это то, что я думаю, что вижу.

@schumannd К вашему сведению, сегодня утром мы выпустили @sentry/react-native 1.10.0 [EDIT: whoops, should be 1.1.0 ], который обновляет его зависимость для использования последней версии @sentry/browser (которая включает возврат - true вместо false исправление, упомянутое выше).

@lobsterkatie, похоже, последняя версия @ sentry / react -native

Поэтому попытка установить 1.10.0 не работает. Как мне исправить?

@schumannd @lobsterkatie означало 1.1.0 , так как это было тогда, когда мы обновили 5.9.0 до @sentry/browser . Параметр обработчика, устанавливающий уровень ведения журнала, также должен нормально работать в последней версии @sentry/react-native .

Была ли эта страница полезной?
0 / 5 - 0 рейтинги