Здравствуйте, Васильич, Вы писали:
В>Почему так, куда пропадает стек в первом случае? Я уже и гуглил, и изучал исходники proc_lib, gen_*, sys — ну нет там чего-то такого, что могло бы приводить к такому результату. А без стектрейсов отлаживать просто нереально. Сейчас приходится отказываться от proc_lib и даваемых ей преимуществ, запускать через spawn().
По-моему есть путаница в вопросах исключений и трейса. Попробую разъяснить.
При возникновении исключения никакого трейса в нем нет, только тип и причина. Трейс добавляет оператор catch и только для исключений рантайма.
Можно сравнить вывод catch для разных видов исключений.
Здесь видно что catch не позволяет однозначно опрделить тип исключения и было ли оно вообще.
Это мешало полноценно их использовать, и поэтому появилась конструкция try...catch...end .
При обработке исключения в try..catch..end трейса нет:
Что касается изначальной проблемы, то похоже что proc_lib в случае ошибок генерит специальный отчет crash_report,
который обычным логгером игнорируется, для вывода crash_report нужно запустить sasl или свой обработчик.
Для отладки кстати удобно включить трассировку вызовов функций.
У Joel Reymont есть удобная обертка для включения выключения трассировки всех функций конкретного модуля — здесь.
Вот столкнулся с новой проблемой. Итак, есть несколько процессов, при запуске которых используются функции из модулей proc_lib и sys. Что-то вроде:
start_link(Args) ->
proc_lib:start_link(?MODULE, init,
[self(), Args]).
init(Parent, Args) ->
% Тут проводим инициализацию процесса
% ...
Debug = sys:debug_options([]),
State = #state{...},
proc_lib:init_ack(Parent, {ok, self()}),
loop(State, Parent, Debug).
loop(State, Parent, Debug) ->
receive
% Тут обрабатываем свои сообщения
% ...
{system, From, Request} ->
sys:handle_system_msg(
Request, From, Parent, ?MODULE, Debug, State)
end.
В общем, все как рекомендуется в доке. Теперь, как только в любом из этих процессов возникает рантаймовая ошибка, например function_clause, то процесс падает с причиной ошибки просто function_clause, без стектрейса:
=INFO REPORT==== 9-Sep-2009::23:20:16 ===
application: stp
exited: function_clause
type: temporary
=ERROR REPORT==== 9-Sep-2009::23:20:16 ===
** Generic server <0.53.0> terminating
** Last message in was {'DOWN',#Ref<0.0.0.58>,process,<0.48.0>,
function_clause}
** When Server state == {state,#Port<0.738>,undefined,<0.48.0>,undefined,on,
false,false,on,connected,undefined,0,
[#Port<0.736>,#Port<0.737>],
#Port<0.739>,#Port<0.740>}
** Reason for termination ==
** {stopped,{'EXIT',<0.48.0>,function_clause}}
При этом, процессы из этого же приложения, которые запускались через обычный spawn_link() или которые реализованы через стандартные бехавиоры — падают нормально, со стектрейсом:
** Generic server <0.53.0> terminating
** Last message in was {'DOWN',#Ref<0.0.0.58>,process,<0.48.0>,
{function_clause,
[{consumer,crash,[do_it]},
{consumer,handle_info,2},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}}
** When Server state == {state,#Port<0.738>,undefined,<0.48.0>,undefined,on,
false,false,on,connected,undefined,0,
[#Port<0.736>,#Port<0.737>],
#Port<0.739>,#Port<0.740>}
** Reason for termination ==
** {stopped,{'EXIT',<0.48.0>,
{function_clause,[{consumer,crash,[do_it]},
{consumer,handle_info,2},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}}}
Почему так, куда пропадает стек в первом случае? Я уже и гуглил, и изучал исходники proc_lib, gen_*, sys — ну нет там чего-то такого, что могло бы приводить к такому результату. А без стектрейсов отлаживать просто нереально. Сейчас приходится отказываться от proc_lib и даваемых ей преимуществ, запускать через spawn().
Re: [erlang] Почему при краше процесса не видно стектрейс?
Здравствуйте, DmitryMe, Вы писали:
DM>Наверно потому что
DM>
DM>The module sys contains some functions for simple debugging of processes implemented using behaviours
DM>Процесс должен реализовывать один из gen_* шаблонов.
Я тоже так сначала думал. Но ведь исходники gen_* шаблонов доступны, они сами построены на proc_lib и sys. И они не делают чего-то этакого, все стандартно, что сделано и у меня. Более того, вчера я наткнулся на еще кое-что.
Допустим есть процесс, который использует для запуска proc_lib (первый процесс из моего первого поста). Когда возникает рантайм-еррор — он падает без стектрейса. Но! Если поймать этот эксепшен вручную и потом сразу его бросить с помощью exit() — то все работает нормально! Я даже сделал специальную функцию:
runtime_error_workaround(R) ->
case R of
{'EXIT', Reason} -> exit(Reason);
_ -> R
end.
То есть, в изначальном эксепшене, который генерируется интерпретатором, присутствует вся необходимая инфа, в том числе и стектрейс (это я проверил). Если повторно бросить этот эксепшен через exit() — то вся информация из него показывается в error-репорте. Если же этот эксепшен перехватывается самой proc_lib — то стектрейс отсутствует. Такое ощущение, что она его обрезает, хотя судя по ее исходникам такого происходить не должно. Мистика? Или я что-то упускаю?
И у меня еще один вопрос в связи с этим: как можно в отладчике отлаживать системные библиотеки (ту же proc_lib)? Я запускаю отладчик через im(), он позволяет проинтерпретировать мои собственные модули, но не системные. Я хочу установить точку останова на момент, когда proc_lib перехватывает возникающие в процессе исключения, и посмотреть что с ними происходит.
Re[2]: [erlang] Почему при краше процесса не видно стектрейс
Здравствуйте, Васильич, Вы писали:
В>В общем, все как рекомендуется в доке. Теперь, как только в любом из этих процессов возникает рантаймовая ошибка, например function_clause, то процесс падает с причиной ошибки просто function_clause, без стектрейса:
В>=INFO REPORT==== 9-Sep-2009::23:20:16 === В> application: stp В> exited: function_clause В> type: temporary
В>=ERROR REPORT==== 9-Sep-2009::23:20:16 === В>** Generic server <0.53.0> terminating В>** Last message in was {'DOWN',#Ref<0.0.0.58>,process,<0.48.0>, В> function_clause} В>** When Server state == {state,#Port<0.738>,undefined,<0.48.0>,undefined,on, В> false,false,on,connected,undefined,0, В> Port<0.736>,#Port<0.737>, В> #Port<0.739>,#Port<0.740>} В>** Reason for termination == В>** {stopped,{'EXIT',<0.48.0>,function_clause}}
Что-то я тут не понимаю, "кто на ком стоял". Сообщение приходит из 0.53.0. Причём причина его завершения напоминает то, что он слинкован с 0.48.0, получил exit для него и тут же завершился. В этом случае вообще-то трейс не имеет смысла: если Вы trap_exit'ом это не перехватываете, 'EXIT' убьёт линкованный процесс в любом состоянии. Кто именно был порождён через proc_lib? 0.48.0? Но у него же номер меньше, значит, наверняка был порождён раньше. Так кто у вас по-разному рождается в данных примерах — 0.48.0 или 0.53.0?
Кстати, рекомендую дать каждому процессу имя через register(), для отладки это полезнее.
Далее, SASL у Вас при этом запущен или нет? Если нет — рекомендую таки запустить, с ним возникают более подробные и осмысленные сообщения о происходящем.
В>Почему так, куда пропадает стек в первом случае? Я уже и гуглил, и изучал исходники proc_lib, gen_*, sys — ну нет там чего-то такого, что могло бы приводить к такому результату. А без стектрейсов отлаживать просто нереально. Сейчас приходится отказываться от proc_lib и даваемых ей преимуществ, запускать через spawn().
Ну вообще-то ничего не мешает сделать адекватный этому костыль в собственной функции верхнего уровня в процессе, по типу
Здравствуйте, netch80, Вы писали:
В>>=INFO REPORT==== 9-Sep-2009::23:20:16 === В>> application: stp В>> exited: function_clause В>> type: temporary
В>>=ERROR REPORT==== 9-Sep-2009::23:20:16 === В>>** Generic server <0.53.0> terminating В>>** Last message in was {'DOWN',#Ref<0.0.0.58>,process,<0.48.0>, В>> function_clause} В>>** When Server state == {state,#Port<0.738>,undefined,<0.48.0>,undefined,on, В>> false,false,on,connected,undefined,0, В>> Port<0.736>,#Port<0.737>, В>> #Port<0.739>,#Port<0.740>} В>>** Reason for termination == В>>** {stopped,{'EXIT',<0.48.0>,function_clause}}
N>Что-то я тут не понимаю, "кто на ком стоял". Сообщение приходит из 0.53.0. Причём причина его завершения напоминает то, что он слинкован с 0.48.0, получил exit для него и тут же завершился. В этом случае вообще-то трейс не имеет смысла: если Вы trap_exit'ом это не перехватываете, 'EXIT' убьёт линкованный процесс в любом состоянии. Кто именно был порождён через proc_lib? 0.48.0? Но у него же номер меньше, значит, наверняка был порождён раньше. Так кто у вас по-разному рождается в данных примерах — 0.48.0 или 0.53.0?
0.48.0 — процесс, который крашится. 0.53.0 — этот процесс крутит odbc:init (ODBC используется этим самым моим процессом).
N>Кстати, рекомендую дать каждому процессу имя через register(), для отладки это полезнее.
Дал.
N>Далее, SASL у Вас при этом запущен или нет? Если нет — рекомендую таки запустить, с ним возникают более подробные и осмысленные сообщения о происходящем.
SASL не был запущен. Запустил. В целом, информации стало намного больше и я даже выцепил вот такие строки:
crasher:
initial call: odbc_import:init/4
pid: <0.57.0>
registered_name: odbc_import
exception error: no function clause matching
odbc_import:check_integer(atom)
Исходный function_clause по-прежнему без стектрейса. Однако в exception error наконец стало видно, кто сгенерировал эксепшен (odbc_import:check_integer(atom)). Такое ощущение, что proc_lib каким-то образом модифицирует эксепшен, убирая оттуда стектрейс. Хотя по исходникам этого не видно.
N>Ну вообще-то ничего не мешает сделать адекватный этому костыль в собственной функции верхнего уровня в процессе, по типу
N>