Про сообщения об ошибках интерпретатора Эрлэнга
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.06 22:35
Оценка:
То что выдает интерпретатор Эрлэнга в качестве сообщений об ошибках назвать сообщениями об ошибках мой язык не поворачивается.

Собвственно вопрос в том, есть ли что-то (патчи, хаки, ...) что позволяет увидить более менее оумысленные сообщения об ошибках?

Ну, и естесвнно вопрос. Что привело к такой жути?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Про сообщения об ошибках интерпретатора Эрлэнга
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 16.10.06 04:30
Оценка: 4 (1) +2
VladD2,

VD>То что выдает интерпретатор Эрлэнга в качестве сообщений об ошибках назвать сообщениями об ошибках мой язык не поворачивается.


VD>Собвственно вопрос в том, есть ли что-то (патчи, хаки, ...) что позволяет увидить более менее оумысленные сообщения об ошибках?


VD>Ну, и естесвнно вопрос. Что привело к такой жути?


Надеюсь что ты не об этом (здесь имхо всё прозрачно)

./io_layer.erl:224: variable 'Insert' is unbound

а об этом

=ERROR REPORT==== 16-Oct-2006::11:16:04 ===
Error in process <0.72.0> with exit value: {undef,[{io_layer,dostart,[<0.72.0>]},{io_layer,test1,0}]}


Сообщение об ошибке (точнее, код выхода (exit reason)) — это tagged терм. Соответственно все преимущества этого подхода налицо — возможность делать паттерн-матчинг, пересылать другим процессам и т.п, короче создавать функции принимающие этот терм в качестве аргумента. Недостаток тоже на лицо — трудность восприятия. По крайней мере пока не появится навык видеть в этом терме смысл.

Весь "хак", который в данном случае нужен, это функция description(E) -> ... Честно говоря, лень её лабать, проще терм просмотреть.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
report_exit
От: Mamut Швеция http://dmitriid.com
Дата: 17.10.06 07:44
Оценка: 32 (2) +1
В мейллисте мне ответили, прислав следующий патч для shell.erl:

Index: shell.erl
===================================================================
RCS file: /hipe/otp/lib/stdlib/src/shell.erl,v
retrieving revision 1.8
diff -u -r1.8 shell.erl
--- shell.erl    24 Jan 2006 11:46:11 -0000    1.8
+++ shell.erl    11 Apr 2006 20:52:30 -0000
@@ -248,10 +248,77 @@
     {'EXIT', Pid, Res} ->
         {Res, Eval};
     {'EXIT', Eval, Reason} ->
-        io:fwrite("** exited: ~P **\n", [Reason, ?LINEMAX]),
+        report_exit(Reason),
         get_command1(Pid, start_eval(Bs, RT, Ds), Bs, RT, Ds)
     end.
 
+report_exit(Reason) ->
+    {Term,Trace} = analyze_exit(Reason),
+    io:fwrite("** exited: ~P **\n~s", [Term, ?LINEMAX, Trace]).
+
+analyze_exit({Term, Stack}=Reason) when is_list(Stack) ->
+    case is_stacktrace(Stack) of
+    true ->
+        {Term, format_stacktrace(Stack)};
+    false ->
+        {Reason, ""}
+    end;
+analyze_exit(Reason) ->
+    {Reason, ""}.
+
+is_stacktrace([]) ->
+    true;
+is_stacktrace([{M,F,A}|Fs]) when is_atom(M), is_atom(F), is_integer(A) ->
+    is_stacktrace(Fs);
+is_stacktrace([{M,F,As}|Fs]) when is_atom(M), is_atom(F), is_list(As) ->
+    is_stacktrace(Fs);
+is_stacktrace(_) ->
+    false.
+
+format_stacktrace(Stack) ->
+    format_stacktrace(Stack,"in function","in call from").
+
+format_stacktrace([{M,F,A}|Fs],Pre,Pre1) when is_integer(A) ->
+    [io_lib:fwrite("  ~s ~w:~w/~w\n", [Pre,M,F,A])
+     | format_stacktrace(Fs,Pre1,Pre1)];
+format_stacktrace([{M,F,As}|Fs],Pre,Pre1) when is_list(As) ->
+    A = length(As),
+    C = case is_op(M,F,A) of
+        true when A == 1 ->
+        [A1] = As,
+        io_lib:fwrite("~s ~s", [F,format_arg(A1)]);
+        true when A == 2 ->
+        [A1, A2] = As,
+        io_lib:fwrite("~s ~s ~s",
+                  [format_arg(A1),F,format_arg(A2)]);
+        false ->
+        io_lib:fwrite("~w(~s)", [F,format_arglist(As)])
+    end,
+    [io_lib:fwrite("  ~s ~w:~w/~w\n    called as ~s\n",
+           [Pre,M,F,A,C])
+     | format_stacktrace(Fs,Pre1,Pre1)];
+format_stacktrace([],_Pre,_Pre1) ->
+    "".
+
+format_arg(A) ->
+    io_lib:fwrite("~P",[A,?LINEMAX]).
+
+format_arglist([A]) ->
+    format_arg(A);
+format_arglist([A|As]) ->
+    [io_lib:fwrite("~P,",[A,?LINEMAX]) | format_arglist(As)];
+format_arglist([]) ->
+    "".
+
+is_op(erlang, F, A) ->
+    erl_internal:arith_op(F, A)
+    orelse erl_internal:bool_op(F, A)
+    orelse erl_internal:comp_op(F, A)
+    orelse erl_internal:list_op(F, A)
+    orelse erl_internal:send_op(F, A);
+is_op(_M, _F, _A) ->
+    false.
+
 prompt(N) ->
     case is_alive() of
     true -> {format,"(~s)~w> ",[node(),N]};
@@ -407,7 +474,7 @@
         Ev ! {shell_rep,self(),ok},
         shell_rep(Ev, Bs0, RT, Ds);
     {'EXIT',Ev,Reason} ->            % It has exited unnaturally
-        io:fwrite("** exited: ~P **\n", [Reason,?LINEMAX]),
+        report_exit(Reason),
         {{'EXIT',Reason},start_eval(Bs0, RT, Ds0), Bs0, Ds0};
     {'EXIT',_Id,interrupt} ->        % Someone interrupted us
         exit(Ev, kill),
... << RSDN@Home 1.2.0 alpha rev. 655>>


dmitriid.comGitHubLinkedIn
Re[2]: Про сообщения об ошибках интерпретатора Эрлэнга
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.10.06 13:27
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Надеюсь что ты не об этом (здесь имхо всё прозрачно)

LCR>./io_layer.erl:224: variable 'Insert' is unbound

А как такое получить то? У меня что-то все второй вариант появляется.

LCR>Сообщение об ошибке (точнее, код выхода (exit reason)) — это tagged терм. Соответственно все преимущества этого подхода налицо — возможность делать паттерн-матчинг, пересылать другим процессам и т.п, короче создавать функции принимающие этот терм в качестве аргумента.


Зачем мне что-то делать с сообщением об ошибке? Мне нужно его прочесть и понять. Ну, еще неплохо было бы дабал-кликнув перейти к месту ошибке в исходном файле.

LCR>Недостаток тоже на лицо — трудность восприятия. По крайней мере пока не появится навык видеть в этом терме смысл.


На фиг такие навыки. Привыкая к маразму сам не заметишь как станешь маразматиком.

LCR>Весь "хак", который в данном случае нужен, это функция description(E) -> ... Честно говоря, лень её лабать, проще терм просмотреть.


Я и не хочу лабать. Вот только мне кажется, что должен был хоть кто-то попытаться решить эту проблему. Неужели никто ее так и не решил?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: report_exit
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.10.06 14:47
Оценка:
Здравствуйте, Mamut, Вы писали:

M>В мейллисте мне ответили, прислав следующий патч для shell.erl:


Уже не плохо. А готовый экзешниг нельзя куда-нибудь выложить?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Про сообщения об ошибках интерпретатора Эрлэнга
От: faulx  
Дата: 17.10.06 18:09
Оценка: 3 (1)
Можно, я встряну?

Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Lazy Cjow Rhrr, Вы писали:


LCR>>Надеюсь что ты не об этом (здесь имхо всё прозрачно)

LCR>>./io_layer.erl:224: variable 'Insert' is unbound

VD>А как такое получить то? У меня что-то все второй вариант появляется.


Такое получается, когда ошибка компиляции. Страшное сообщение — когда ошибка выполнения.

LCR>>Сообщение об ошибке (точнее, код выхода (exit reason)) — это tagged терм. Соответственно все преимущества этого подхода налицо — возможность делать паттерн-матчинг, пересылать другим процессам и т.п, короче создавать функции принимающие этот терм в качестве аргумента.


VD>Зачем мне что-то делать с сообщением об ошибке? Мне нужно его прочесть и понять. Ну, еще неплохо было бы дабал-кликнув перейти к месту ошибке в исходном файле.


По сообщению об ошибке компиляции перейти можно (по крайней мере мой Емакс переходит). По сообщению времени исполнения перейти, естественно, труднее.

LCR>>Недостаток тоже на лицо — трудность восприятия. По крайней мере пока не появится навык видеть в этом терме смысл.


VD>На фиг такие навыки. Привыкая к маразму сам не заметишь как станешь маразматиком.


Теперь философия. Зачем нужно такое сообщение об ошибке? Дело в том, что одна из фишек Эрланга — это как раз обработка ошибок. Ошибок времени исполнения, разумеется. Когда вы вводите в интерпретаторе что-нибудь вроде
1=0.

происходит ошибка времени исполнения
{{badmatch,0},[{erl_eval,expr,3}]}

(В данном случае все просто. Произошла ошибка badmatch, т.е. ошибка сопоставления с образцом, 0 — это то значение, которое не было сопоставлено. Тут бы еще показать то с значение, с которым не сопоставлено, т.е. в данном случае, 1, но чего нет, того нет. Список [{erl_eval,expr,3}] — это стек вызовов, в данном случае, неглубокий.)

Идея в том, что этот терм (сообщение об ошибке + стек) можно перехватить в вашей же программе, обработать, скинуть в лог, отправить по почте — словом, обработать. И тут, согласитесь, чем больше информации, тем лучше.

Теперь об интерпретаторе. Конечно, можно было бы в интерпретаторе вместо сообщения {{badmatch,0},[{erl_eval,expr,3}]} поставить что-нибудь многословное, вежливо объясняющее, что же произошло. Но нужно ли это? Зачем вообще нужен интепретатор? Чтобы вычислить какое-нибудь выражение, вызвать функцию, и посмотреть, что будет. Вот оно нам честно и говорит, что будет. И ровно то же самое (с точностью до стека) будет и при выполнении программы. Так что всегда можно посмотреть, какая ошибка выдается при вычислении какого-либо выражения и знать, что будет при вычислении этого выражения в реальной работе, когда интерпретатора уже и рядом не будет.
Re[4]: Про сообщения об ошибках интерпретатора Эрлэнга
От: faulx  
Дата: 17.10.06 18:47
Оценка: :)
Вдогонку.

В принципе, можно сделать свой обработчик ошибок интерпретатора. Интерпретатор сообщает об ошибках два раза: один раз пишет сам, а другой раз прилетает сообщение от процесса error_logger. Так вот, этому error_logger-у можно поставить свой обработчик, в котором можно делать все, что угодно. Т.е., создаем модуль my_handler.erl

-module(my_handler).
-behaviour(gen_event).

-export([start/0, stop/0]).
-export([report/1]).
-export([init/1, handle_event/2, terminate/2]).

start() ->
    error_logger:add_report_handler(my_handler).

stop() ->
    error_logger:delete_report_handler(my_handler).

report(MyError) ->
    error_logger:error_report(my_error, MyError).

init(_Arg) ->
    {ok, []}.

handle_event({error, Gleader, {Pid, Format, Data}}, State) ->
    io:format("==PREVED=======~n", []),
    io:format("По Эрлангу - низач0т!~n"),
    {ok, State};
handle_event(_Event, State) ->
    {ok, State}.

terminate(_Arg, _State) ->
    ok.


Теперь подключаем его: компилируем и вызваем my_handler:start(). Все, добавился еще один обработчик, и интерпретатор будет при ошибке писать то, что мы выводим в handle_event.

Здесь есть одна засада: информация об ошибке в переменной Data приходит уже в виде текстовой строки вида "Error in process <0.30.0> with exit value: {{badmatch,0},[{erl_eval,expr,3}]}". Это прописывается где-то очень глубоко. В принципе, если есть желание, можно ее распарсить, перевести и напечатать в любом удобном виде, хотя, конечно, изврат.
Re[4]: Про сообщения об ошибках интерпретатора Эрлэнга
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.10.06 21:20
Оценка: 3 (1)
Здравствуйте, faulx, Вы писали:

F>По сообщению об ошибке компиляции перейти можно (по крайней мере мой Емакс переходит). По сообщению времени исполнения перейти, естественно, труднее.


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

F>Теперь философия. Зачем нужно такое сообщение об ошибке? Дело в том, что одна из фишек Эрланга — это как раз обработка ошибок. Ошибок времени исполнения, разумеется. Когда вы вводите в интерпретаторе что-нибудь вроде

F>
1=0.

F>происходит ошибка времени исполнения
F>
F>{{badmatch,0},[{erl_eval,expr,3}]}
F>

F>(В данном случае все просто. Произошла ошибка badmatch, т.е. ошибка сопоставления с образцом, 0 — это то значение, которое не было сопоставлено. Тут бы еще показать то с значение, с которым не сопоставлено, т.е. в данном случае, 1, но чего нет, того нет. Список [{erl_eval,expr,3}] — это стек вызовов, в данном случае, неглубокий.)

Откровенно говоря я в этом сообщении вижу много лишнего "шума" (мусора) и не вижу важной информации — строки в которой произошла ошибка.

F>Идея в том, что этот терм (сообщение об ошибке + стек) можно перехватить в вашей же программе, обработать, скинуть в лог, отправить по почте — словом, обработать. И тут, согласитесь, чем больше информации, тем лучше.


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

F>Теперь об интерпретаторе. Конечно, можно было бы в интерпретаторе вместо сообщения {{badmatch,0},[{erl_eval,expr,3}]} поставить что-нибудь многословное, вежливо объясняющее, что же произошло.


Ага. Я бы только сказал не "многословное", а "легко понятное".

F> Но нужно ли это?


Очень нужно. Удобство — это одна из важнейших черт любого продукта. А уж языка программирования в первую очередь.

F> Зачем вообще нужен интепретатор?


Незнаю. Я кроме интерпретатора пакетных файлов ОС (и то редко) других не использую.

F> Чтобы вычислить какое-нибудь выражение, вызвать функцию, и посмотреть, что будет. Вот оно нам честно и говорит, что будет. И ровно то же самое (с точностью до стека) будет и при выполнении программы.


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

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


Все же я не понимаю почему при этом нельзя выводить и человекочитаемое сообщение.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: report_exit
От: Mamut Швеция http://dmitriid.com
Дата: 18.10.06 06:15
Оценка:
M>>В мейллисте мне ответили, прислав следующий патч для shell.erl:

VD>Уже не плохо. А готовый экзешниг нельзя куда-нибудь выложить?


В Эрланге экзешник?

Это надо патчить $ERL_TOP/lib/stdlib-1.14/src/shell.erl
... << RSDN@Home 1.2.0 alpha rev. 655>>


dmitriid.comGitHubLinkedIn
Re[3]: report_exit
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.10.06 00:26
Оценка:
Здравствуйте, Mamut, Вы писали:

M>В Эрланге экзешник?


Понял. Привычка, однако.

M>Это надо патчить $ERL_TOP/lib/stdlib-1.14/src/shell.erl


Надеюсь тортила патч сест...
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: report_exit
От: Mamut Швеция http://dmitriid.com
Дата: 19.10.06 06:43
Оценка:
M>>В Эрланге экзешник?

VD>Понял. Привычка, однако.




M>>Это надо патчить $ERL_TOP/lib/stdlib-1.14/src/shell.erl


VD>Надеюсь тортила патч сест...


Это не знаю Как минимум, можно ручками и потом натравить на него erlc (компилятор)
... << RSDN@Home 1.2.0 alpha rev. 655>>


dmitriid.comGitHubLinkedIn
Re[5]: report_exit
От: gandalfgrey  
Дата: 19.10.06 09:08
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Это не знаю Как минимум, можно ручками и потом натравить на него erlc (компилятор)

Патч был в формате diff'а ?
Re[6]: report_exit
От: Mamut Швеция http://dmitriid.com
Дата: 19.10.06 12:28
Оценка:
M>>Это не знаю Как минимум, можно ручками и потом натравить на него erlc (компилятор)
G>Патч был в формате diff'а ?

А вот он
Автор: Mamut
Дата: 17.10.06
... << RSDN@Home 1.2.0 alpha rev. 655>>


dmitriid.comGitHubLinkedIn
Re[7]: report_exit
От: gandalfgrey  
Дата: 19.10.06 13:18
Оценка:
Здравствуйте, Mamut, Вы писали:

M>А вот он
Автор: Mamut
Дата: 17.10.06

Оно самое !
Был вызван diff -u
Ничего ручками делать не надо, а надо diff --merge ...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.