Capture detailed Erlang logs on connection failure
This commit is contained in:
parent
8f217bd3fa
commit
bd639b8b2c
|
|
@ -0,0 +1,175 @@
|
|||
%% 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 Developer of the Original Code is GoPivotal, Inc.
|
||||
%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
|
||||
%%
|
||||
-module(rabbit_error_logger_handler).
|
||||
|
||||
-behaviour(gen_event).
|
||||
|
||||
%% API
|
||||
-export([start_link/0, add_handler/0]).
|
||||
|
||||
%% gen_event callbacks
|
||||
-export([init/1, handle_event/2, handle_call/2,
|
||||
handle_info/2, terminate/2, code_change/3]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
-record(state, {report = []}).
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% Creates an event manager
|
||||
%%
|
||||
%% @spec start_link() -> {ok, Pid} | {error, Error}
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
start_link() ->
|
||||
gen_event:start_link({local, ?SERVER}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% Adds an event handler
|
||||
%%
|
||||
%% @spec add_handler() -> ok | {'EXIT', Reason} | term()
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
add_handler() ->
|
||||
gen_event:add_handler(?SERVER, ?MODULE, []).
|
||||
|
||||
%%%===================================================================
|
||||
%%% gen_event callbacks
|
||||
%%%===================================================================
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @doc
|
||||
%% Whenever a new event handler is added to an event manager,
|
||||
%% this function is called to initialize the event handler.
|
||||
%%
|
||||
%% @spec init(Args) -> {ok, State}
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
init([]) ->
|
||||
{ok, #state{}}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @doc
|
||||
%% Whenever an event manager receives an event sent using
|
||||
%% gen_event:notify/2 or gen_event:sync_notify/2, this function is
|
||||
%% called for each installed event handler to handle the event.
|
||||
%%
|
||||
%% @spec handle_event(Event, State) ->
|
||||
%% {ok, State} |
|
||||
%% {swap_handler, Args1, State1, Mod2, Args2} |
|
||||
%% remove_handler
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
handle_event({info_report, _Gleader, {_Pid, _Type,
|
||||
{net_kernel, {'EXIT', _, Reason}}}},
|
||||
#state{report = Report} = State) ->
|
||||
NewReport = case format(Reason) of
|
||||
[] -> Report;
|
||||
Formatted -> [Formatted | Report]
|
||||
end,
|
||||
{ok, State#state{report = NewReport}};
|
||||
handle_event(_Event, State) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @doc
|
||||
%% Whenever an event manager receives a request sent using
|
||||
%% gen_event:call/3,4, this function is called for the specified
|
||||
%% event handler to handle the request.
|
||||
%%
|
||||
%% @spec handle_call(Request, State) ->
|
||||
%% {ok, Reply, State} |
|
||||
%% {swap_handler, Reply, Args1, State1, Mod2, Args2} |
|
||||
%% {remove_handler, Reply}
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
handle_call(get_connection_report, State) ->
|
||||
{ok, lists:reverse(State#state.report), State#state{report = []}};
|
||||
handle_call(_Request, State) ->
|
||||
Reply = ok,
|
||||
{ok, Reply, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @doc
|
||||
%% This function is called for each installed event handler when
|
||||
%% an event manager receives any other message than an event or a
|
||||
%% synchronous request (or a system message).
|
||||
%%
|
||||
%% @spec handle_info(Info, State) ->
|
||||
%% {ok, State} |
|
||||
%% {swap_handler, Args1, State1, Mod2, Args2} |
|
||||
%% remove_handler
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
handle_info(_Info, State) ->
|
||||
{ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @doc
|
||||
%% Whenever an event handler is deleted from an event manager, this
|
||||
%% function is called. It should be the opposite of Module:init/1 and
|
||||
%% do any necessary cleaning up.
|
||||
%%
|
||||
%% @spec terminate(Reason, State) -> void()
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
terminate(_Reason, _State) ->
|
||||
ok.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @doc
|
||||
%% Convert process state when code is changed
|
||||
%%
|
||||
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
format({check_dflag_xnc_failed, _What}) ->
|
||||
{" * Remote node is using an incompatible Erlang version ~n", []};
|
||||
format({recv_challenge_failed, no_node, Node}) ->
|
||||
{" * Hostname mismatch ~p~n", [Node]};
|
||||
format({recv_challenge_failed, Error}) ->
|
||||
{" * Distribution failed unexpectedly while waiting for challenge: ~p~n", [Error]};
|
||||
format({recv_challenge_ack_failed, bad_cookie}) ->
|
||||
{" * Authorisation rejected by local node, please verify the cookie~n", []};
|
||||
format({recv_challenge_ack_failed, {error, closed}}) ->
|
||||
{" * Authorisation rejected by remote node, please verify the cookie~n", []};
|
||||
format({recv_status_failed, not_allowed}) ->
|
||||
{" * Host not in remote allowed list (see net_kernel:allow/1)~n", []};
|
||||
format({recv_status_failed, {error, closed}}) ->
|
||||
{" * Remote host closed the connection. Is the Erlang distribution using TLS?~n", []};
|
||||
format(setup_timer_timeout) ->
|
||||
{" * Remote connection has timed out. Is the Erlang distribution using TLS?~n", []};
|
||||
format(_) ->
|
||||
[].
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
-define(EPMD_TIMEOUT, 30000).
|
||||
-define(TCP_DIAGNOSTIC_TIMEOUT, 5000).
|
||||
-define(ERROR_LOGGER_HANDLER, rabbit_error_logger_handler).
|
||||
|
||||
%%----------------------------------------------------------------------------
|
||||
%% Specs
|
||||
|
|
@ -62,12 +63,21 @@ names(Hostname) ->
|
|||
end.
|
||||
|
||||
diagnostics(Nodes) ->
|
||||
verbose_erlang_distribution(true),
|
||||
NodeDiags = [{"~nDIAGNOSTICS~n===========~n~n"
|
||||
"attempted to contact: ~p~n", [Nodes]}] ++
|
||||
[diagnostics_node(Node) || Node <- Nodes] ++
|
||||
current_node_details(),
|
||||
verbose_erlang_distribution(false),
|
||||
rabbit_misc:format_many(lists:flatten(NodeDiags)).
|
||||
|
||||
verbose_erlang_distribution(true) ->
|
||||
net_kernel:verbose(1),
|
||||
error_logger:add_report_handler(?ERROR_LOGGER_HANDLER);
|
||||
verbose_erlang_distribution(false) ->
|
||||
net_kernel:verbose(0),
|
||||
error_logger:delete_report_handler(?ERROR_LOGGER_HANDLER).
|
||||
|
||||
current_node_details() ->
|
||||
[{"~ncurrent node details:~n- node name: ~w", [node()]},
|
||||
case init:get_argument(home) of
|
||||
|
|
@ -136,11 +146,7 @@ dist_broken_diagnostics(Name, Host, NamePorts) ->
|
|||
[{" * epmd reports node '~s' running on port ~b", [Name, Port]} |
|
||||
case diagnose_connect(Host, Port) of
|
||||
ok ->
|
||||
[{" * TCP connection succeeded but Erlang distribution "
|
||||
"failed~n"
|
||||
" * suggestion: hostname mismatch?~n"
|
||||
" * suggestion: is the cookie set correctly?~n"
|
||||
" * suggestion: is the Erlang distribution using TLS?", []}];
|
||||
connection_succeeded_diagnostics();
|
||||
{error, Reason} ->
|
||||
[{" * can't establish TCP connection, reason: ~s~n"
|
||||
" * suggestion: blocked by firewall?",
|
||||
|
|
@ -148,6 +154,20 @@ dist_broken_diagnostics(Name, Host, NamePorts) ->
|
|||
end]
|
||||
end.
|
||||
|
||||
connection_succeeded_diagnostics() ->
|
||||
case gen_event:call(error_logger, ?ERROR_LOGGER_HANDLER, get_connection_report) of
|
||||
[] ->
|
||||
[{" * TCP connection succeeded but Erlang distribution "
|
||||
"failed~n"
|
||||
" * suggestion: hostname mismatch?~n"
|
||||
" * suggestion: is the cookie set correctly?~n"
|
||||
" * suggestion: is the Erlang distribution using TLS?", []}];
|
||||
Report ->
|
||||
[{" * TCP connection succeeded but Erlang distribution "
|
||||
"failed~n", []}]
|
||||
++ Report
|
||||
end.
|
||||
|
||||
diagnose_connect(Host, Port) ->
|
||||
case inet:gethostbyname(Host) of
|
||||
{ok, #hostent{h_addrtype = Family}} ->
|
||||
|
|
|
|||
Loading…
Reference in New Issue