Как вы воспроизводите ошибки, которые происходят спорадически?


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

отказ от ответственности: эта ошибка существует и я его видел. Это не pebkac или что-то подобное.

каковы общие подсказки, чтобы воспроизвести этот вид ошибки?

28 61

28 ответов:

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

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

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

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

нет общего ответа на вопрос, но вот что я нашел:

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

  2. работать в обратном направлении, и относиться к нему как научной расследование. Начните с ошибки, то, что вы видите неправильно. Развивайте гипотезы о том, что может вызвать его (это творческая/творческая часть, искусство, к которому не у всех есть талант) - и это очень помогает узнать, как работает код. Для каждой из этих гипотез (предпочтительно отсортированных по тому, что вы считаете наиболее вероятным - опять же чистая интуиция здесь), разработайте тест, который пытается устранить его как причину, и проверьте гипотезу. Любое невыполнение прогноза не означает, что гипотеза неправильный. Проверьте гипотезу, пока она не подтвердится, что она неверна (хотя, поскольку она становится менее вероятной, вы можете сначала перейти к другой гипотезе, просто не сбрасывайте со счетов эту, пока у вас не будет окончательной неудачи).

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

  4. дважды проверьте каждое предположение. Так много раз я видел, что проблема не исправляется быстро, потому что какой-то общий вызов метода не был дополнительно исследован, поэтому проблема просто предполагалась неприменимой. - О, это, это должно быть просто."(См. пункт 1).

Если у вас закончились гипотезы, это обычно вызвано недостаточным знанием системы (это верно, даже если вы сами написали каждую строку кода), и вам нужно запустить и просмотреть код и получить дополнительное представление о системе, чтобы придумать новую идею.

конечно, ни один из вышеперечисленных гарантий ничего, но это подход, который я нашел получает результаты последовательно.

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

на этой частоте 1/100 я бы сказал, что первое, что нужно сделать, это обрабатывать исключения и регистрировать что-либо в любом месте, или вы можете потратить еще одну неделю на охоту за этой ошибкой. Также составьте приоритетный список потенциально чувствительных артикуляций и функций в вашем проект. Например : 1 - многопоточность 2 - дикие указатели/ свободные массивы 3-опора на устройства ввода так далее. Это поможет вам сегментировать области, которые вы можете использовать грубую силу до перерыва, как это предлагается другими плакатами.

поскольку это язык-агностик, я упомяну несколько аксиом отладки.

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

другой пользователь, тот же компьютер? Тот же пользователь, другой компьютер? Является ли это явление сильно периодическим? Изменяет ли перезагрузка периодичность?

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

пользователи использовали приложение по-разному. Пользователь А обычно используется горячая клавиша для вызова действия, а пользователь B использует экранный элемент управления. Разница в поведении пользователя будет каскадировать в видимую ошибку через несколько действий позже.

любая разница, которая влияет на поведение ошибки, должна быть исследована, даже если это не имеет смысла.

есть хороший шанс, что ваше приложение MTWIDNTBMT (многопоточный, когда он не должен быть многопоточным), или, может быть, просто многопоточный (чтобы быть вежливым). Хороший способ воспроизвести спорадические ошибки в многопоточных приложениях-это разбрызгать такой код вокруг (C#):

Random rnd = new Random();
System.Threading.Thread.Sleep(rnd.Next(2000));

и/или этот:

for (int i = 0; i < 4000000000; i++)
{
    // tight loop
}

для имитации потоков, выполняющих свои задачи в разное время, чем обычно, или связывая процессор для длинных отрезков.

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

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

изменить: еще немного мыслей: если это приложение gui, запустите тесты с помощью инструмента автоматизации qa, который позволяет воспроизводить макросы. Если это приложение типа службы, попробуйте придумать хотя бы догадку о том, что происходит, а затем программно создать шаблоны использования "freak", которые будут использовать код, который вы подозреваете. Создать более высокие, чем обычно, нагрузки и т. д.

какая среда разработки? Для C++ лучше всего использовать VMWare Workstation record / replay, см.: http://stackframe.blogspot.com/2007/04/workstation-60-and-death-of.html

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

попробуйте добавить код в приложение, чтобы отслеживать ошибку автоматически, как только это произойдет (или даже предупредить вас по почте / SMS)

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

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

все вышеперечисленное, плюс бросьте на него какой-то грубый силовой софт-робот, который является полу случайным, и scater много утверждает/проверяет (c/c++, вероятно, похожий на другие langs) через код

тонны регистрации и тщательный обзор кода являются вашими единственными вариантами.

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

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

допустим, я начинаю с производственного приложения.

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

  2. Я повторяю Шаг 1, пока у меня нет хорошей идеи о том, где я могу начать отладку кода в отладчике

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

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

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

  6. Если вы до сих пор ничего не получили, вернитесь к шагу 1 и сделайте еще одну итерацию.

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

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

сказав, что нет серебряной пули. Я чувствую твою боль.

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

вы можете посмотреть оформление по договору

наряду с большим терпением, тихой молитвой и проклятием вам понадобится:

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

НТН.

предполагая, что вы находитесь на Windows, и ваша "ошибка" - это сбой или какое-то повреждение в неуправляемом коде (C/C++), а затем взгляните на Средство Проверки Приложений из Microsoft. Инструмент имеет ряд остановок, которые могут быть включены для проверки вещей во время выполнения. Если у вас есть представление о сценарии, в котором происходит ошибка, попробуйте выполнить сценарий (или версию сценария стресса) с запущенным AppVerifer. Убедитесь, что либо включить pageheap в AppVerifier, либо рассмотреть компиляция кода с помощью параметра / RTCcsu (см. http://msdn.microsoft.com/en-us/library/8wtf2dfz.aspx для получения дополнительной информации).

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

внимательно прочитайте трассировку стека и попытайтесь угадать, что может произойти; затем попробуйте отследить\log каждую строку кода, которая потенциально может вызвать проблемы.

сосредоточьтесь на утилизации ресурсов; многие подлые спорадические ошибки, которые я нашел, были связаны с close\dispose things :).

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

http://code.google.com/p/elmah/

Это спасло меня только сегодня в ловле очень случайной ошибки, которая происходила во время процесса регистрации

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

Они в основном выходят ночью.... в основном

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

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

Это зависит (как вы говорите), но некоторые вещи, которые удобны с этим может быть

  • сразу же входит в отладчик, когда возникает проблема, и сбрасывает все потоки (или эквивалент, например, немедленно сбрасывает ядро или что-то еще.)
  • работает с включенным журналированием, но в остальном полностью в режиме выпуска/производства. (Это возможно в некоторых случайных средах, таких как c и rails, но не во многих других.)
  • делать вещи, чтобы сделать краевые условия на машине хуже... сила низкая память / высокая нагрузка / больше потоков / обслуживание большего количества запросов
  • убедитесь, что вы на самом деле слушаете то, что пользователи сталкиваются с проблемой на самом деле говорят. Убедившись, что они на самом деле объясняют соответствующие детали. Это, кажется, тот, который ломает людей в этой области много. Попытка воспроизвести неправильную проблему скучна.
  • привыкайте к чтению сборки, которая была произведена путем оптимизации компиляторы. Это, кажется, иногда останавливает людей, и это не применимо ко всем языкам / платформам, но это может помочь
  • будьте готовы признать, что это вина ваша (застройщика). Не попасть в ловушку, настаивая на том, что код идеален.
  • иногда вам нужно на самом деле отслеживать проблему на машине, на которой это происходит.

@p. marino - недостаточно rep для комментариев =/

tl; dr-сбои сборки из-за времени суток

Вы упомянули время суток, и это привлекло мое внимание. Была ошибка однажды кто-то остался позже на работе на ночь, пытался построить и совершить, прежде чем они ушли и продолжали получать неудачу. В конце концов они сдались и пошли домой. Когда они поймали на следующее утро, он построил отлично, они совершили (вероятно, должны были быть более подозрительными=]), и сборка работала для всех. Через неделю или две кто-то задержался допоздна и неожиданно потерпел неудачу в сборке. Оказывается, в коде была ошибка, которая сделала любую сборку после 7pm break >.>

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

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

нанять тестеров!

Это сработало для действительно странных гейзенбагов. (Я бы также рекомендовал получить копию "отладки" Дэйва Арганса, эти идеи частично получены из его идей!)

(0) Проверьте ОЗУ системы, используя что-то вроде Memtest86!

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

он не терпит неудачу в 100% случаев, поэтому вы должны заставить его терпеть неудачу чаще.

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

смотрите, если он все еще терпит неудачу. Не чаще ?

храните правильные записи тестов и меняйте только одну переменную за раз!

в худшем случае вы используете джиг и вы тестируете в течение нескольких недель, чтобы получить значимую статистику. Это трудно; но помните, что джиг делает свою работу.

у меня нет потоков и только один процесс, и я не разговариваю с оборудованием

Если в системе нет потоков, нет взаимодействующих процессов и контактов нет аппаратного обеспечения; это сложно; heisenbugs обычно синхронизируются, но в случае no-thread no processes это, скорее всего, неинициализированные данные или данные, используемые после освобождения, либо на куча или стек. Попробуйте использовать шашку, как valgrind.

для проблем с резьбой / несколькими процессами:

попробуйте запустить его на разное количество процессоров. Если он работает на 1, Попробуйте на 4! Попробуйте заставить 4-компьютерную систему на 1. Это в основном гарантирует, что все будет происходить по одному.

Если есть потоки или сообщающиеся процессы, это может вытряхнуть ошибки.

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

наоборот, попробуйте идти медленнее на timeslices.

затем вы устанавливаете тестовый джиг, работающий с отладчиком(АМИ), прикрепленным повсюду, и ждете, пока тестовый джиг остановится на ошибке.

если все остальное не удается, Поместите оборудование в морозильную камеру и запустите его там. Сроки все будут перемещенный.

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

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

1) анализировать исходный код и определить, каковы источники недетерминизма в приложении, то есть каковы аспекты, которые могут принимать ваше приложение через различные пути выполнения (например, пользовательский ввод, сигналы ОС)

2) записать их в следующий раз, когда вы запустите приложение

3) Когда ваше приложение снова терпит неудачу, у вас есть шаги для воспроизведения сбоя в вашем журнале.

Если ваш журнал еще не воспроизвести ошибку, то вы имеете дело с ошибка параллелизма. В этом случае вы должны взглянуть на то, как ваше приложение обращается к общим переменным. Не пытайтесь записывать доступ к общим переменным, потому что вы будете записывать слишком много данных, тем самым вызывая серьезные замедления и большие журналы. К сожалению, я мало что могу сказать, что помогло бы вам воспроизвести ошибки параллелизма, потому что исследование все еще имеет долгий путь в этой теме. Лучшее, что я могу сделать, это предоставить ссылку на самый последний аванс (до сих пор) в тема детерминированного воспроизведения ошибок параллелизма:

http://www.gsd.inesc-id.pt/~nmachado/software/Symbiosis_Tutorial.html

с наилучшими пожеланиями

используйте расширенный репортер аварии. В среде Delphi у нас есть EurekaLog и MadExcept. Другие инструменты существуют в других средах. Или вы можете диагностировать дамп ядра. Вы ищете трассировку стека, которая покажет вам, где он взрывается, как он туда попал, что в памяти и т. д.. Также полезно иметь скриншот приложения, если это взаимодействие с пользователем. И информация о машине, на которой он разбился (версия ОС и патч, что еще работает в то время и т. д..) Оба инструмента, которые я упомянул, могут это сделать.

Если это то, что происходит с несколькими пользователями, но вы не можете воспроизвести его, и они могут, посидите с ними и посмотрите. Если это не очевидно, переключите сиденья-вы "едете", и они говорят вам, что делать. Таким образом, вы раскроете тонкие проблемы юзабилити. дважды щелкните кнопку с одним щелчком мыши, например, инициируя повторный вход в событие OnClick. Что-то в этом роде. Если пользователи удаленные, используйте WebEx, Wink и т. д., вести запись они разбивают его, так что вы можете анализировать воспроизведение.