Ведение Журнала. В Коробке

Логирование используется в каждом программном продукте, доходящем до стадии производства.

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

В этой части я рассмотрю готовый функционал.



0. Как это работает

Как и другие встроенные утилиты, ведение журнала построено на принципах OTP. Регистратор ошибок Erlang — это менеджер событий (gen_event(3)), зарегистрированный как error_logger. События ошибок, предупреждений и информации отправляются из Erlang RTS и различных приложений в error_logger. По умолчанию они выводятся на консоль.

Изначально error_logger использует очень простой обработчик событий, который буферизует и печатает необработанные сообщения о событиях.

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

Рекомендуется использовать error_logger в своих приложениях для получения универсальных отчетов.

Пользователь может добавлять свои собственные обработчики событий (add_report_handler/1,2).



1. САСЛ

Каждый программист Erlang знает, что такое SASL. Большинство руководств написаны с его использованием.

Мы обязательно включаем SASL при отладке приложений.

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

  
  
  
  
   

root@37221-1:~# erl -boot start_sasl Erlang R13B03 (erts-5.7.4) [source] [rq:1] [async-threads:0] [hipe] [kernel-poll:false] =PROGRESS REPORT==== 11-Mar-2011::19:34:39 === supervisor: {local,sasl_safe_sup} started: [{pid,<0.35.0>}, {name,alarm_handler}, {mfa,{alarm_handler,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::19:34:39 === supervisor: {local,sasl_safe_sup} started: [{pid,<0.36.0>}, {name,overload}, {mfa,{overload,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::19:34:39 === supervisor: {local,sasl_sup} started: [{pid,<0.34.0>}, {name,sasl_safe_sup}, {mfa, {supervisor,start_link, [{local,sasl_safe_sup},sasl,safe]}}, {restart_type,permanent}, {shutdown,infinity}, {child_type,supervisor}] =PROGRESS REPORT==== 11-Mar-2011::19:34:39 === supervisor: {local,sasl_sup} started: [{pid,<0.37.0>}, {name,release_handler}, {mfa,{release_handler,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::19:34:39 === application: sasl started_at: nonode@nohost Eshell V5.7.4 (abort with ^G) 1> application:start(crypto).

=PROGRESS REPORT==== 11-Mar-2011::19:34:54 === supervisor: {local,crypto_sup} started: [{pid,<0.49.0>}, {name,crypto_server}, {mfa,{crypto_server,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::19:34:54 === application: crypto started_at: nonode@nohost ok 2> rb:start().

{error,{"cannot locate report directory", {child,undefined,rb_server, {rb,start_link,[[]]}, temporary,brutal_kill,worker, [rb]}}} 3> =CRASH REPORT==== 11-Mar-2011::19:35:16 === crasher: initial call: rb:init/1 pid: <0.51.0> registered_name: [] exception exit: "cannot locate report directory" in function gen_server:init_it/6 ancestors: [sasl_sup,<0.32.0>] messages: [] links: [<0.33.0>] dictionary: [] trap_exit: true status: running heap_size: 233 stack_size: 24 reductions: 109 neighbours:

SASL включает в себя 3 обработчика событий:
  • sasl_report_tty_h — отчеты супервизора, отчеты о сбоях и прогрессе выводятся на консоль.

  • sasl_report_file_h — отчеты супервизора, отчет о сбое и прогресс выводятся в отдельный файл.

  • error_logger_mf_h — этот логгер обрабатывает все события.

    Он устанавливает обработчик событий log_mf_h (подробнее ниже) в error_logger.

SASL поддерживает определенную конфигурацию, которая подробно описана в документации.

Установка обработчика sasl_report_file_h и sasl_error_logger = {file, FileName} позволит выводить информацию в отдельный файл журнала.

Однако при перезапуске приложения вся старая информация будет удалена (!).



2. log_mf_h

log_mf_h — это обработчик gen_event, который можно установить в любой процесс gen_event. Он сохраняет все события на диск.

Каждое событие сохраняется в двоичном формате.

Для чтения этих журналов можно использовать такое приложение, как Report Browser (rb).

log_mf_h:init/3,4 возвращает аргументы конфигурации для gen_event:add_handler(EventMgr, log_mf_h, Args).

Их можно использовать в любом менеджере событий.



root@37221-1:/home/user# erl -boot start_sasl Erlang R13B03 (erts-5.7.4) [source] [rq:1] [async-threads:0] [hipe] [kernel-poll:false] =PROGRESS REPORT==== 11-Mar-2011::19:48:22 === supervisor: {local,sasl_safe_sup} started: [{pid,<0.35.0>}, {name,alarm_handler}, {mfa,{alarm_handler,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::19:48:22 === supervisor: {local,sasl_safe_sup} started: [{pid,<0.36.0>}, {name,overload}, {mfa,{overload,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::19:48:22 === supervisor: {local,sasl_sup} started: [{pid,<0.34.0>}, {name,sasl_safe_sup}, {mfa, {supervisor,start_link, [{local,sasl_safe_sup},sasl,safe]}}, {restart_type,permanent}, {shutdown,infinity}, {child_type,supervisor}] =PROGRESS REPORT==== 11-Mar-2011::19:48:22 === supervisor: {local,sasl_sup} started: [{pid,<0.37.0>}, {name,release_handler}, {mfa,{release_handler,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::19:48:22 === application: sasl started_at: nonode@nohost Eshell V5.7.4 (abort with ^G) 1> Conf = log_mf_h:init(".

", 1024, 10).

{".

",1024,10,#Fun<log_mf_h.0.56828844>} 2> gen_event:add_handler(error_logger, log_mf_h, Conf).

ok 3> F = fun(N) -> N() end. #Fun<erl_eval.6.13229925> 4> spawn(F).

=ERROR REPORT==== 11-Mar-2011::19:49:59 === Error in process <0.48.0> with exit value: {{badarity,{#Fun<erl_eval.6.13229925>,[]}},[{erlang,apply,2}]} <0.48.0> 5> application:start(crypto).

=PROGRESS REPORT==== 11-Mar-2011::19:50:29 === supervisor: {local,crypto_sup} started: [{pid,<0.54.0>}, {name,crypto_server}, {mfa,{crypto_server,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::19:50:29 === application: crypto started_at: nonode@nohost ok 6> rb:start([{report_dir, ".

"}]).

rb: reading report.done. =PROGRESS REPORT==== 11-Mar-2011::19:50:53 === supervisor: {local,sasl_sup} started: [{pid,<0.56.0>}, {name,rb_server}, {mfa,{rb,start_link,[[{report_dir,".

"}]]}}, {restart_type,temporary}, {shutdown,brutal_kill}, {child_type,worker}] {ok,<0.56.0>} 7> rb:list().

No Type Process Date Time == ==== ======= ==== ==== 3 error <0.25.0> 2011-03-11 19:49:59 2 progress <0.51.0> 2011-03-11 19:50:29 1 progress <0.24.0> 2011-03-11 19:50:29 ok 8> rb:list(error).

No Type Process Date Time == ==== ======= ==== ==== 3 error <0.25.0> 2011-03-11 19:49:59 ok 9> rb:show(3).

ERROR REPORT emulator 2011-03-11 19:49:59 =============================================================================== Error in process <0.48.0> with exit value: {{badarity,{#Fun<erl_eval.6.13229925>,[]}},[{erlang,apply,2}]} ok 10> halt().

root@37221-1:/home/user# ls -1 1 2 index mboga root@37221-1:/home/user#



3. SASL + log_mf_h

Как я писал выше, настройки SASL позволяют использовать log_mf_h для обработки событий.

Для этого в конфигурации SASL необходимо указать следующие параметры:

[{sasl, [ {sasl_error_logger, false}, {error_logger_mf_dir, "/home/user/mboga/log/log_mf_h"}, {error_logger_mf_maxbytes, 1024}, {error_logger_mf_maxfiles, 10} ]}].



Теперь все события будут записываться в указанную директорию.

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

root@37221-1:~# ps aux | grep erlang root 27943 0.0 0.1 1980 368 ? S Mar08 0:01 /usr/lib/erlang/erts-5.7.4/bin/epmd -daemon root 31714 0.5 3.0 13912 8092 ? S 07:37 3:45 /usr/lib/erlang/erts-5.7.4/bin/beam -- -root /usr/lib/erlang -progname erl -- -home /root -- -noshell -pa ebin edit deps/erldis/ebin deps/mochiweb/ebin -boot logging -sname mboga_web_dev -s mboga_web -s reloader root 31944 0.0 0.2 1888 700 pts/1 S+ 20:05 0:00 grep --color=auto erlang root@37221-1:~# erl -boot start_sasl Erlang R13B03 (erts-5.7.4) [source] [rq:1] [async-threads:0] [hipe] [kernel-poll:false] =PROGRESS REPORT==== 11-Mar-2011::20:05:43 === supervisor: {local,sasl_safe_sup} started: [{pid,<0.35.0>}, {name,alarm_handler}, {mfa,{alarm_handler,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::20:05:43 === supervisor: {local,sasl_safe_sup} started: [{pid,<0.36.0>}, {name,overload}, {mfa,{overload,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::20:05:43 === supervisor: {local,sasl_sup} started: [{pid,<0.34.0>}, {name,sasl_safe_sup}, {mfa, {supervisor,start_link, [{local,sasl_safe_sup},sasl,safe]}}, {restart_type,permanent}, {shutdown,infinity}, {child_type,supervisor}] =PROGRESS REPORT==== 11-Mar-2011::20:05:43 === supervisor: {local,sasl_sup} started: [{pid,<0.37.0>}, {name,release_handler}, {mfa,{release_handler,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 11-Mar-2011::20:05:43 === application: sasl started_at: nonode@nohost Eshell V5.7.4 (abort with ^G) 1> rb:start([{report_dir, "/home/user/mboga/log/log_mf_h"}]).

rb: reading report.done. rb: reading report.done. rb: reading report.done. rb: reading report.done. rb: reading report.done. rb: reading report.done. =PROGRESS REPORT==== 11-Mar-2011::20:07:02 === supervisor: {local,sasl_sup} started: [{pid,<0.47.0>}, {name,rb_server}, {mfa, {rb,start_link, [[{report_dir, "/home/user/mboga/log/log_mf_h"}]]}}, {restart_type,temporary}, {shutdown,brutal_kill}, {child_type,worker}] {ok,<0.47.0>} 2> rb:start_log("/home/user/mboga/log/rb.log").

ok 3> rb:list().

No Type Process Date Time == ==== ======= ==== ==== .

29 progress <6800.8.0> 2011-03-10 23:00:44 28 error_report <6800.50.0> 2011-03-10 23:01:10 27 error_report <6800.50.0> 2011-03-10 23:01:10 26 error_report <6800.50.0> 2011-03-10 23:01:11 25 progress <6800.34.0> 2011-03-10 23:02:52 24 progress <6800.34.0> 2011-03-10 23:02:52 .

4 progress <6800.50.0> 2011-03-11 07:37:50 3 progress <6800.29.0> 2011-03-11 07:37:50 2 progress <6800.8.0> 2011-03-11 07:37:50 1 crash_report mochiweb_acceptor 2011-03-11 10:08:03 ok 4> rb:list(crash_report).

No Type Process Date Time == ==== ======= ==== ==== 48 crash_report mochiweb_acceptor 2011-03-10 15:29:26 44 crash_report supervisor_bridge 2011-03-10 22:46:40 41 crash_report reloader 2011-03-10 22:55:04 1 crash_report mochiweb_acceptor 2011-03-11 10:08:03 ok 5> rb:show(1).

ok 6> rb:list(error_report).

No Type Process Date Time == ==== ======= ==== ==== 47 error_report <6800.50.0> 2011-03-10 22:46:40 28 error_report <6800.50.0> 2011-03-10 23:01:10 27 error_report <6800.50.0> 2011-03-10 23:01:10 26 error_report <6800.50.0> 2011-03-10 23:01:11 ok 7> rb:show(27).

ok 8> rb:stop().

ok



root@37221-1:~# cat /home/user/mboga/log/rb.log CRASH REPORT <6768.60.0> 2011-03-11 10:08:03 =============================================================================== Crashing process initial_call {mochiweb_acceptor,init,['Argument__1','Argument__2','Argument__3']} pid <6768.60.0> registered_name [] error_info {error,function_clause, [{mochiweb,new_request, [{#Port<6768.1465>, {"CONNECT",{scheme,"www.google.com","443"},{1,0}}, []}]}, {mochiweb_http,headers,5}, {proc_lib,init_p_do_apply,3}]} ancestors [mboga_web_web,mboga_web_sup,<6768.51.0>] messages [] links [<6768.56.0>,#Port<6768.1465>] dictionary [] trap_exit false status running heap_size 2584 stack_size 24 reductions 59064 ERROR REPORT <6768.75.0> 2011-03-10 23:01:10 =============================================================================== "web request failed" path upload/ type exit what could_not_open_file_for_writing trace [{mboga_web_web,callback,2}, {mochiweb_multipart,feed_mp,2}, {mboga_web_web,upload,2}, {mboga_web_web,loop,3}, {mochiweb_http,headers,5}, {proc_lib,init_p_do_apply,3}] root@37221-1:~#



4. .

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

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

Но об этом в следующий раз.

Теги: #erlang #ведение журнала #Erlang/OTP

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.