1-module(rabbit_prelaunch_errors). 2 3-include_lib("kernel/include/logger.hrl"). 4 5-include_lib("rabbit_common/include/logging.hrl"). 6 7-export([format_error/1, 8 format_exception/3, 9 log_error/1, 10 log_exception/3]). 11 12-define(BOOT_FAILED_HEADER, 13 "\n" 14 "BOOT FAILED\n" 15 "===========\n"). 16 17-define(BOOT_FAILED_FOOTER, 18 "\n"). 19 20log_error(Error) -> 21 Message = format_error(Error), 22 log_message(Message). 23 24format_error({error, {duplicate_node_name, NodeName, NodeHost}}) -> 25 rabbit_misc:format( 26 "ERROR: node with name ~p is already running on host ~p", 27 [NodeName, NodeHost]); 28format_error({error, {epmd_error, NodeHost, EpmdReason}}) -> 29 rabbit_misc:format( 30 "ERROR: epmd error for host ~s: ~s", 31 [NodeHost, rabbit_misc:format_inet_error(EpmdReason)]); 32format_error({error, {invalid_dist_port_range, DistTcpPort}}) -> 33 rabbit_misc:format( 34 "Invalid Erlang distribution TCP port: ~b", [DistTcpPort]); 35format_error({error, {dist_port_already_used, Port, not_erlang, Host}}) -> 36 rabbit_misc:format( 37 "ERROR: could not bind to distribution port ~b on host ~s. It could " 38 "be in use by another process or cannot be bound to (e.g. due to a " 39 "security policy)", [Port, Host]); 40format_error({error, {dist_port_already_used, Port, Name, Host}}) -> 41 rabbit_misc:format( 42 "ERROR: could not bind to distribution port ~b, it is in use by " 43 "another node: ~s@~s", [Port, Name, Host]); 44format_error({error, {erlang_dist_running_with_unexpected_nodename, 45 Unexpected, Node}}) -> 46 rabbit_misc:format( 47 "Erlang distribution running with another node name (~s) " 48 "than the configured one (~s)", 49 [Unexpected, Node]); 50format_error({bad_config_entry_decoder, missing_passphrase}) -> 51 rabbit_misc:format( 52 "Missing passphrase or missing passphrase read method in " 53 "`config_entry_decoder`", []); 54format_error({config_decryption_error, {key, Key}, _Msg}) -> 55 rabbit_misc:format( 56 "Error while decrypting key '~p'. Please check encrypted value, " 57 "passphrase, and encryption configuration~n", 58 [Key]); 59format_error({error, {timeout_waiting_for_tables, AllNodes, _}}) -> 60 Suffix = 61 "~nBACKGROUND~n==========~n~n" 62 "This cluster node was shut down while other nodes were still running.~n" 63 "To avoid losing data, you should start the other nodes first, then~n" 64 "start this one. To force this node to start, first invoke~n" 65 "\"rabbitmqctl force_boot\". If you do so, any changes made on other~n" 66 "cluster nodes after this one was shut down may be lost.", 67 {Message, Nodes} = 68 case AllNodes -- [node()] of 69 [] -> {rabbit_misc:format( 70 "Timeout contacting cluster nodes. Since RabbitMQ was" 71 " shut down forcefully~nit cannot determine which nodes" 72 " are timing out.~n" ++ Suffix, []), 73 []}; 74 Ns -> {rabbit_misc:format( 75 "Timeout contacting cluster nodes: ~p.~n" ++ Suffix, 76 [Ns]), 77 Ns} 78 end, 79 Message ++ "\n" ++ rabbit_nodes_common:diagnostics(Nodes); 80format_error({error, {cannot_log_to_file, unknown, Reason}}) -> 81 rabbit_misc:format( 82 "failed to initialised logger: ~p~n", 83 [Reason]); 84format_error({error, {cannot_log_to_file, LogFile, 85 {cannot_create_parent_dirs, _, Reason}}}) -> 86 rabbit_misc:format( 87 "failed to create parent directory for log file at '~s', reason: ~s~n", 88 [LogFile, file:format_error(Reason)]); 89format_error({error, {cannot_log_to_file, LogFile, Reason}}) -> 90 rabbit_misc:format( 91 "failed to open log file at '~s', reason: ~s", 92 [LogFile, file:format_error(Reason)]); 93format_error(Error) -> 94 rabbit_misc:format("Error during startup: ~p", [Error]). 95 96log_exception(Class, Exception, Stacktrace) -> 97 Message = format_exception(Class, Exception, Stacktrace), 98 log_message(Message). 99 100format_exception(Class, Exception, Stacktrace) -> 101 StacktraceStrs = [begin 102 case proplists:get_value(line, Props) of 103 undefined when is_list(ArgListOrArity) -> 104 io_lib:format( 105 " ~ts:~ts/~b~n" 106 " args: ~p", 107 [Mod, Fun, length(ArgListOrArity), 108 ArgListOrArity]); 109 undefined when is_integer(ArgListOrArity) -> 110 io_lib:format( 111 " ~ts:~ts/~b", 112 [Mod, Fun, ArgListOrArity]); 113 Line when is_list(ArgListOrArity) -> 114 io_lib:format( 115 " ~ts:~ts/~b, line ~b~n" 116 " args: ~p", 117 [Mod, Fun, length(ArgListOrArity), Line, 118 ArgListOrArity]); 119 Line when is_integer(ArgListOrArity) -> 120 io_lib:format( 121 " ~ts:~ts/~b, line ~b", 122 [Mod, Fun, ArgListOrArity, Line]) 123 end 124 end 125 || {Mod, Fun, ArgListOrArity, Props} <- Stacktrace], 126 ExceptionStr = io_lib:format("~ts:~0p", [Class, Exception]), 127 rabbit_misc:format( 128 "Exception during startup:~n~n~s~n~n~s", 129 [ExceptionStr, string:join(StacktraceStrs, "\n")]). 130 131log_message(Message) -> 132 Lines = string:split( 133 ?BOOT_FAILED_HEADER ++ 134 Message ++ 135 ?BOOT_FAILED_FOOTER, 136 [$\n], 137 all), 138 ?LOG_ERROR( 139 "~s", [string:join(Lines, "\n")], 140 #{domain => ?RMQLOG_DOMAIN_PRELAUNCH}), 141 lists:foreach( 142 fun(Line) -> 143 io:format(standard_error, "~s~n", [Line]) 144 end, Lines), 145 timer:sleep(1000), 146 ok. 147