diff options
| author | Matthias Radestock <matthias@lshift.net> | 2008-09-08 16:19:01 +0100 |
|---|---|---|
| committer | Matthias Radestock <matthias@lshift.net> | 2008-09-08 16:19:01 +0100 |
| commit | 453584601c3d7652eb8a08d6e63cf273caf43521 (patch) | |
| tree | fdf9a5b6f11d9f6954623c909055735bcc99c31e /src | |
| parent | e5bf57a323e4727ce005b0d0e6f883921a9c21c6 (diff) | |
| parent | 5587def78e0cf978a492af3a91796e479331d9a9 (diff) | |
| download | rabbitmq-server-git-453584601c3d7652eb8a08d6e63cf273caf43521.tar.gz | |
merge bug19200 into default
Diffstat (limited to 'src')
| -rw-r--r-- | src/rabbit.erl | 131 | ||||
| -rw-r--r-- | src/rabbit_control.erl | 8 | ||||
| -rw-r--r-- | src/rabbit_error_logger_file_h.erl | 74 | ||||
| -rw-r--r-- | src/rabbit_misc.erl | 26 | ||||
| -rw-r--r-- | src/rabbit_sasl_report_file_h.erl | 86 | ||||
| -rw-r--r-- | src/rabbit_tests.erl | 184 |
6 files changed, 469 insertions, 40 deletions
diff --git a/src/rabbit.erl b/src/rabbit.erl index 9ab6b1a68c..c6ef1749f2 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -27,10 +27,12 @@ -behaviour(application). --export([start/0, stop/0, stop_and_halt/0, status/0]). +-export([start/0, stop/0, stop_and_halt/0, status/0, rotate_logs/1]). -export([start/2, stop/1]). +-export([log_location/1]). + -import(application). -import(mnesia). -import(lists). @@ -46,13 +48,18 @@ -ifdef(use_specs). +-type(log_location() :: 'tty' | 'undefined' | string()). +-type(file_suffix() :: binary()). + -spec(start/0 :: () -> 'ok'). -spec(stop/0 :: () -> 'ok'). -spec(stop_and_halt/0 :: () -> 'ok'). +-spec(rotate_logs/1 :: (file_suffix()) -> 'ok' | {'error', any()}). -spec(status/0 :: () -> [{running_applications, [{atom(), string(), string()}]} | {nodes, [node()]} | {running_nodes, [node()]}]). +-spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()). -endif. @@ -60,7 +67,7 @@ start() -> try - ok = ensure_working_log_config(), + ok = ensure_working_log_handlers(), ok = rabbit_mnesia:ensure_mnesia_dir(), ok = start_applications(?APPS) after @@ -85,6 +92,15 @@ status() -> [{running_applications, application:which_applications()}] ++ rabbit_mnesia:status(). +rotate_logs(BinarySuffix) -> + Suffix = binary_to_list(BinarySuffix), + log_rotation_result(rotate_logs(log_location(kernel), + Suffix, + rabbit_error_logger_file_h), + rotate_logs(log_location(sasl), + Suffix, + rabbit_sasl_report_file_h)). + %%-------------------------------------------------------------------- manage_applications(Iterate, Do, Undo, SkipError, ErrorTag, Apps) -> @@ -186,6 +202,21 @@ stop(_State) -> %--------------------------------------------------------------------------- +log_location(Type) -> + case application:get_env(Type, case Type of + kernel -> error_logger; + sasl -> sasl_error_logger + end) of + {ok, {file, File}} -> File; + {ok, false} -> undefined; + {ok, tty} -> tty; + {ok, silent} -> undefined; + {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}}); + _ -> undefined + end. + +%--------------------------------------------------------------------------- + print_banner() -> {ok, Product} = application:get_key(id), {ok, Version} = application:get_key(vsn), @@ -194,7 +225,9 @@ print_banner() -> ?PROTOCOL_VERSION_MAJOR, ?PROTOCOL_VERSION_MINOR, ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]), io:format("Logging to ~p~nSASL logging to ~p~n~n", - [error_log_location(), sasl_log_location()]). + [log_location(kernel), log_location(sasl)]). + + start_child(Mod) -> {ok,_} = supervisor:start_child(rabbit_sup, @@ -202,6 +235,43 @@ start_child(Mod) -> transient, 100, worker, [Mod]}), ok. +ensure_working_log_handlers() -> + Handlers = gen_event:which_handlers(error_logger), + ok = ensure_working_log_handler(error_logger_file_h, + rabbit_error_logger_file_h, + error_logger_tty_h, + log_location(kernel), + Handlers), + + ok = ensure_working_log_handler(sasl_report_file_h, + rabbit_sasl_report_file_h, + sasl_report_tty_h, + log_location(sasl), + Handlers), + ok. + +ensure_working_log_handler(OldFHandler, NewFHandler, TTYHandler, + LogLocation, Handlers) -> + case LogLocation of + undefined -> ok; + tty -> case lists:member(TTYHandler, Handlers) of + true -> ok; + false -> + throw({error, {cannot_log_to_tty, + TTYHandler, not_installed}}) + end; + _ -> case lists:member(NewFHandler, Handlers) of + true -> ok; + false -> case rotate_logs(LogLocation, "", + OldFHandler, NewFHandler) of + ok -> ok; + {error, Reason} -> + throw({error, {cannot_log_to_file, + LogLocation, Reason}}) + end + end + end. + maybe_insert_default_data() -> case rabbit_mnesia:is_db_empty() of true -> insert_default_data(); @@ -223,40 +293,25 @@ start_builtin_amq_applications() -> %%restart ok. -ensure_working_log_config() -> - case error_logger:logfile(filename) of - {error, no_log_file} -> - %% either no log file was configured or opening it failed. - case application:get_env(kernel, error_logger) of - {ok, {file, Filename}} -> - case filelib:ensure_dir(Filename) of - ok -> ok; - {error, Reason1} -> - throw({error, {cannot_log_to_file, - Filename, Reason1}}) - end, - case error_logger:logfile({open, Filename}) of - ok -> ok; - {error, Reason2} -> - throw({error, {cannot_log_to_file, - Filename, Reason2}}) - end; - _ -> ok - end; - _Filename -> ok +rotate_logs(File, Suffix, Handler) -> + rotate_logs(File, Suffix, Handler, Handler). + +rotate_logs(File, Suffix, OldHandler, NewHandler) -> + case File of + undefined -> ok; + tty -> ok; + _ -> gen_event:swap_handler( + error_logger, + {OldHandler, swap}, + {NewHandler, {File, Suffix}}) end. -error_log_location() -> - case error_logger:logfile(filename) of - {error,no_log_file} -> tty; - File -> File - end. - -sasl_log_location() -> - case application:get_env(sasl, sasl_error_logger) of - {ok, {file, File}} -> File; - {ok, false} -> undefined; - {ok, tty} -> tty; - {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}}); - _ -> undefined - end. +log_rotation_result({error, MainLogError}, {error, SaslLogError}) -> + {error, {{cannot_rotate_main_logs, MainLogError}, + {cannot_rotate_sasl_logs, SaslLogError}}}; +log_rotation_result({error, MainLogError}, ok) -> + {error, {cannot_rotate_main_logs, MainLogError}}; +log_rotation_result(ok, {error, SaslLogError}) -> + {error, {cannot_rotate_sasl_logs, SaslLogError}}; +log_rotation_result(ok, ok) -> + ok. diff --git a/src/rabbit_control.erl b/src/rabbit_control.erl index eb24b78270..bc588279b4 100644 --- a/src/rabbit_control.erl +++ b/src/rabbit_control.erl @@ -73,6 +73,7 @@ Available commands: force_reset cluster <ClusterNode> ... status + rotate_logs [Suffix] add_user <UserName> <Password> delete_user <UserName> @@ -129,6 +130,13 @@ action(status, Node, []) -> io:format("~n~p~n", [Res]), ok; +action(rotate_logs, Node, []) -> + io:format("Reopening logs for node ~p ...", [Node]), + call(Node, {rabbit, rotate_logs, [""]}); +action(rotate_logs, Node, Args = [Suffix]) -> + io:format("Rotating logs to files with suffix ~p ...", [Suffix]), + call(Node, {rabbit, rotate_logs, Args}); + action(add_user, Node, Args = [Username, _Password]) -> io:format("Creating user ~p ...", [Username]), call(Node, {rabbit_access_control, add_user, Args}); diff --git a/src/rabbit_error_logger_file_h.erl b/src/rabbit_error_logger_file_h.erl new file mode 100644 index 0000000000..d67b02ef42 --- /dev/null +++ b/src/rabbit_error_logger_file_h.erl @@ -0,0 +1,74 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developers of the Original Code are LShift Ltd., +%% Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd. +%% +%% Portions created by LShift Ltd., Cohesive Financial Technologies +%% LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008 +%% LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit +%% Technologies Ltd.; +%% +%% All Rights Reserved. +%% +%% Contributor(s): ______________________________________. +%% + +-module(rabbit_error_logger_file_h). + +-behaviour(gen_event). + +-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). + +%% rabbit_error_logger_file_h is a wrapper around the error_logger_file_h +%% module because the original's init/1 does not match properly +%% with the result of closing the old handler when swapping handlers. +%% The first init/1 additionally allows for simple log rotation +%% when the suffix is not the empty string. + +%% Used only when swapping handlers in log rotation +init({{File, Suffix}, []}) -> + case rabbit_misc:append_file(File, Suffix) of + ok -> ok; + {error, Error} -> + rabbit_log:error("Failed to append contents of " ++ + "log file '~s' to '~s':~n~p~n", + [File, [File, Suffix], Error]) + end, + init(File); +%% Used only when swapping handlers and the original handler +%% failed to terminate or was never installed +init({{File, _}, error}) -> + init(File); +%% Used only when swapping handlers without performing +%% log rotation +init({File, []}) -> + init(File); +init({_File, _Type} = FileInfo) -> + error_logger_file_h:init(FileInfo); +init(File) -> + error_logger_file_h:init(File). + +handle_event(Event, State) -> + error_logger_file_h:handle_event(Event, State). + +handle_info(Event, State) -> + error_logger_file_h:handle_info(Event, State). + +handle_call(Event, State) -> + error_logger_file_h:handle_call(Event, State). + +terminate(Reason, State) -> + error_logger_file_h:terminate(Reason, State). + +code_change(OldVsn, State, Extra) -> + error_logger_file_h:code_change(OldVsn, State, Extra). diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl index 11ab0caf9f..3e4ed8f36f 100644 --- a/src/rabbit_misc.erl +++ b/src/rabbit_misc.erl @@ -26,6 +26,7 @@ -module(rabbit_misc). -include("rabbit.hrl"). -include("rabbit_framing.hrl"). +-include_lib("kernel/include/file.hrl"). -export([method_record_type/1, polite_pause/0, polite_pause/1]). -export([die/1, frame_error/2, protocol_error/3, protocol_error/4]). @@ -41,6 +42,7 @@ -export([intersperse/2, upmap/2, map_in_order/2]). -export([guid/0, string_guid/1, binstring_guid/1]). -export([dirty_read_all/1, dirty_foreach_key/2, dirty_dump_log/1]). +-export([append_file/2]). -import(mnesia). -import(lists). @@ -66,7 +68,7 @@ -spec(get_config/2 :: (atom(), A) -> A). -spec(set_config/2 :: (atom(), any()) -> 'ok'). -spec(dirty_read/1 :: ({atom(), any()}) -> {'ok', any()} | not_found()). --spec(r/3 :: (vhost(), K, name()) -> r(K) when is_subtype(K, atom())). +-spec(r/3 :: (vhost(), K, resource_name()) -> r(K) when is_subtype(K, atom())). -spec(r/2 :: (vhost(), K) -> #resource{virtual_host :: vhost(), kind :: K, name :: '_'} @@ -92,6 +94,7 @@ -spec(dirty_foreach_key/2 :: (fun ((any()) -> any()), atom()) -> 'ok' | 'aborted'). -spec(dirty_dump_log/1 :: (string()) -> 'ok' | {'error', any()}). +-spec(append_file/2 :: (string(), string()) -> 'ok' | {'error', any()}). -endif. @@ -333,3 +336,24 @@ dirty_dump_log1(LH, {K, Terms}) -> dirty_dump_log1(LH, {K, Terms, BadBytes}) -> io:format("Bad Chunk, ~p: ~p~n", [BadBytes, Terms]), dirty_dump_log1(LH, disk_log:chunk(LH, K)). + + +append_file(File, Suffix) -> + case file:read_file_info(File) of + {ok, FInfo} -> append_file(File, FInfo#file_info.size, Suffix); + {error, enoent} -> append_file(File, 0, Suffix); + Error -> Error + end. + +append_file(_, _, "") -> + ok; +append_file(File, 0, Suffix) -> + case file:open([File, Suffix], [append]) of + {ok, Fd} -> file:close(Fd); + Error -> Error + end; +append_file(File, _, Suffix) -> + case file:read_file(File) of + {ok, Data} -> file:write_file([File, Suffix], Data, [append]); + Error -> Error + end. diff --git a/src/rabbit_sasl_report_file_h.erl b/src/rabbit_sasl_report_file_h.erl new file mode 100644 index 0000000000..3374d63d0b --- /dev/null +++ b/src/rabbit_sasl_report_file_h.erl @@ -0,0 +1,86 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developers of the Original Code are LShift Ltd., +%% Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd. +%% +%% Portions created by LShift Ltd., Cohesive Financial Technologies +%% LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008 +%% LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit +%% Technologies Ltd.; +%% +%% All Rights Reserved. +%% +%% Contributor(s): ______________________________________. +%% + +-module(rabbit_sasl_report_file_h). + +-behaviour(gen_event). + +-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). + +%% rabbit_sasl_report_file_h is a wrapper around the sasl_report_file_h +%% module because the original's init/1 does not match properly +%% with the result of closing the old handler when swapping handlers. +%% The first init/1 additionally allows for simple log rotation +%% when the suffix is not the empty string. + +%% Used only when swapping handlers and performing +%% log rotation +init({{File, Suffix}, []}) -> + case rabbit_misc:append_file(File, Suffix) of + ok -> ok; + {error, Error} -> + rabbit_log:error("Failed to append contents of " ++ + "sasl log file '~s' to '~s':~n~p~n", + [File, [File, Suffix], Error]) + end, + init(File); +%% Used only when swapping handlers and the original handler +%% failed to terminate or was never installed +init({{File, _}, error}) -> + init(File); +%% Used only when swapping handlers without +%% doing any log rotation +init({File, []}) -> + init(File); +init({_File, _Type} = FileInfo) -> + sasl_report_file_h:init(FileInfo); +init(File) -> + sasl_report_file_h:init({File, sasl_error_logger_type()}). + +handle_event(Event, State) -> + sasl_report_file_h:handle_event(Event, State). + +handle_info(Event, State) -> + sasl_report_file_h:handle_info(Event, State). + +handle_call(Event, State) -> + sasl_report_file_h:handle_call(Event, State). + +terminate(Reason, State) -> + sasl_report_file_h:terminate(Reason, State). + +code_change(OldVsn, State, Extra) -> + sasl_report_file_h:code_change(OldVsn, State, Extra). + +%%---------------------------------------------------------------------- + +sasl_error_logger_type() -> + case application:get_env(sasl, errlog_type) of + {ok, error} -> error; + {ok, progress} -> progress; + {ok, all} -> all; + {ok, Bad} -> throw({error, {wrong_errlog_type, Bad}}); + _ -> all + end. diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl index 6f43b08a38..fff02d7363 100644 --- a/src/rabbit_tests.erl +++ b/src/rabbit_tests.erl @@ -29,6 +29,8 @@ -import(lists). +-include_lib("kernel/include/file.hrl"). + test_content_prop_roundtrip(Datum, Binary) -> Types = [element(1, E) || E <- Datum], Values = [element(2, E) || E <- Datum], @@ -38,7 +40,9 @@ test_content_prop_roundtrip(Datum, Binary) -> all_tests() -> passed = test_parsing(), passed = test_topic_matching(), + passed = test_log_management(), passed = test_app_management(), + passed = test_log_management_during_startup(), passed = test_cluster_management(), passed = test_user_management(), passed. @@ -136,6 +140,134 @@ test_app_management() -> ok = control_action(status, []), passed. +test_log_management() -> + MainLog = rabbit:log_location(kernel), + SaslLog = rabbit:log_location(sasl), + Suffix = ".1", + + %% prepare basic logs + file:delete([MainLog, Suffix]), + file:delete([SaslLog, Suffix]), + + %% simple logs reopening + ok = control_action(rotate_logs, []), + [true, true] = empty_files([MainLog, SaslLog]), + ok = test_logs_working(MainLog, SaslLog), + + %% simple log rotation + ok = control_action(rotate_logs, [Suffix]), + [true, true] = non_empty_files([[MainLog, Suffix], [SaslLog, Suffix]]), + [true, true] = empty_files([MainLog, SaslLog]), + ok = test_logs_working(MainLog, SaslLog), + + %% reopening logs with log rotation performed first + ok = clean_logs([MainLog, SaslLog], Suffix), + ok = control_action(rotate_logs, []), + ok = file:rename(MainLog, [MainLog, Suffix]), + ok = file:rename(SaslLog, [SaslLog, Suffix]), + ok = test_logs_working([MainLog, Suffix], [SaslLog, Suffix]), + ok = control_action(rotate_logs, []), + ok = test_logs_working(MainLog, SaslLog), + + %% log rotation on empty file + ok = clean_logs([MainLog, SaslLog], Suffix), + ok = control_action(rotate_logs, []), + ok = control_action(rotate_logs, [Suffix]), + [true, true] = empty_files([[MainLog, Suffix], [SaslLog, Suffix]]), + + %% original main log file is not writable + ok = make_files_non_writable([MainLog]), + {error, {cannot_rotate_main_logs, _}} = control_action(rotate_logs, []), + ok = clean_logs([MainLog], Suffix), + ok = add_log_handlers([{rabbit_error_logger_file_h, MainLog}]), + + %% original sasl log file is not writable + ok = make_files_non_writable([SaslLog]), + {error, {cannot_rotate_sasl_logs, _}} = control_action(rotate_logs, []), + ok = clean_logs([SaslLog], Suffix), + ok = add_log_handlers([{rabbit_sasl_report_file_h, SaslLog}]), + + %% logs with suffix are not writable + ok = control_action(rotate_logs, [Suffix]), + ok = make_files_non_writable([[MainLog, Suffix], [SaslLog, Suffix]]), + ok = control_action(rotate_logs, [Suffix]), + ok = test_logs_working(MainLog, SaslLog), + + %% original log files are not writable + ok = make_files_non_writable([MainLog, SaslLog]), + {error, {{cannot_rotate_main_logs, _}, + {cannot_rotate_sasl_logs, _}}} = control_action(rotate_logs, []), + + %% logging directed to tty (handlers were removed in last test) + ok = clean_logs([MainLog, SaslLog], Suffix), + ok = application:set_env(sasl, sasl_error_logger, tty), + ok = application:set_env(kernel, error_logger, tty), + ok = control_action(rotate_logs, []), + [{error, enoent}, {error, enoent}] = empty_files([MainLog, SaslLog]), + + %% rotate logs when logging is turned off + ok = application:set_env(sasl, sasl_error_logger, false), + ok = application:set_env(kernel, error_logger, silent), + ok = control_action(rotate_logs, []), + [{error, enoent}, {error, enoent}] = empty_files([MainLog, SaslLog]), + + %% cleanup + ok = application:set_env(sasl, sasl_error_logger, {file, SaslLog}), + ok = application:set_env(kernel, error_logger, {file, MainLog}), + ok = add_log_handlers([{rabbit_error_logger_file_h, MainLog}, + {rabbit_sasl_report_file_h, SaslLog}]), + passed. + +test_log_management_during_startup() -> + MainLog = rabbit:log_location(kernel), + SaslLog = rabbit:log_location(sasl), + + %% start application with simple tty logging + ok = control_action(stop_app, []), + ok = application:set_env(kernel, error_logger, tty), + ok = application:set_env(sasl, sasl_error_logger, tty), + ok = add_log_handlers([{error_logger_tty_h, []}, + {sasl_report_tty_h, []}]), + ok = control_action(start_app, []), + + %% start application with tty logging and + %% proper handlers not installed + ok = control_action(stop_app, []), + ok = error_logger:tty(false), + ok = delete_log_handlers([sasl_report_tty_h]), + ok = case catch control_action(start_app, []) of + ok -> exit(got_success_but_expected_failure); + {error, {cannot_log_to_tty, _, _}} -> ok + end, + + %% fix sasl logging + ok = application:set_env(sasl, sasl_error_logger, + {file, SaslLog}), + + %% start application with logging to invalid directory + TmpLog = "/tmp/rabbit-tests/test.log", + file:delete(TmpLog), + ok = application:set_env(kernel, error_logger, {file, TmpLog}), + + ok = delete_log_handlers([rabbit_error_logger_file_h]), + ok = add_log_handlers([{error_logger_file_h, MainLog}]), + ok = case catch control_action(start_app, []) of + ok -> exit(got_success_but_expected_failure); + {error, {cannot_log_to_file, _, _}} -> ok + end, + + %% start application with standard error_logger_file_h + %% handler not installed + ok = application:set_env(kernel, error_logger, {file, MainLog}), + ok = control_action(start_app, []), + ok = control_action(stop_app, []), + + %% start application with standard sasl handler not installed + %% and rabbit main log handler installed correctly + ok = delete_log_handlers([rabbit_sasl_report_file_h]), + ok = control_action(start_app, []), + passed. + test_cluster_management() -> %% 'cluster' and 'reset' should only work if the app is stopped @@ -203,7 +335,6 @@ test_cluster_management() -> end, ok = control_action(start_app, []), - passed. test_cluster_management2(SecondaryNode) -> @@ -329,6 +460,8 @@ test_user_management() -> passed. +%--------------------------------------------------------------------- + control_action(Command, Args) -> control_action(Command, node(), Args). control_action(Command, Node, Args) -> @@ -340,3 +473,52 @@ control_action(Command, Node, Args) -> io:format("failed.~n"), Other end. + +empty_files(Files) -> + [case file:read_file_info(File) of + {ok, FInfo} -> FInfo#file_info.size == 0; + Error -> Error + end || File <- Files]. + +non_empty_files(Files) -> + [case EmptyFile of + {error, Reason} -> {error, Reason}; + _ -> not(EmptyFile) + end || EmptyFile <- empty_files(Files)]. + +test_logs_working(MainLogFile, SaslLogFile) -> + ok = rabbit_log:error("foo bar"), + ok = error_logger:error_report(crash_report, [foo, bar]), + %% give the error loggers some time to catch up + timer:sleep(50), + [true, true] = non_empty_files([MainLogFile, SaslLogFile]), + ok. + +clean_logs(Files, Suffix) -> + [begin + ok = delete_file(File), + ok = delete_file([File, Suffix]) + end || File <- Files], + ok. + +delete_file(File) -> + case file:delete(File) of + ok -> ok; + {error, enoent} -> ok; + Error -> Error + end. + +make_files_non_writable(Files) -> + [ok = file:write_file_info(File, #file_info{mode=0}) || + File <- Files], + ok. + +add_log_handlers(Handlers) -> + [ok = error_logger:add_report_handler(Handler, Args) || + {Handler, Args} <- Handlers], + ok. + +delete_log_handlers(Handlers) -> + [[] = error_logger:delete_report_handler(Handler) || + Handler <- Handlers], + ok. |
