1%% This Source Code Form is subject to the terms of the Mozilla Public
2%% License, v. 2.0. If a copy of the MPL was not distributed with this
3%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
4%%
5%% Copyright (c) 2007-2021 VMware, Inc. or its affiliates.  All rights reserved.
6%%
7
8-module(rabbit).
9
10-include_lib("eunit/include/eunit.hrl").
11-include_lib("kernel/include/logger.hrl").
12-include_lib("rabbit_common/include/logging.hrl").
13
14-ignore_xref({rabbit_direct, force_event_refresh, 1}).
15-ignore_xref({rabbit_networking, force_connection_event_refresh, 1}).
16%% Transitional step until we can require Erlang/OTP 21 and
17%% use the now recommended try/catch syntax for obtaining the stack trace.
18-compile(nowarn_deprecated_function).
19
20-behaviour(application).
21
22-export([start/0, boot/0, stop/0,
23         stop_and_halt/0, await_startup/0, await_startup/1, await_startup/3,
24         status/0, is_running/0, alarms/0,
25         is_running/1, environment/0, rotate_logs/0, force_event_refresh/1,
26         start_fhc/0]).
27
28-export([start/2, stop/1, prep_stop/1]).
29-export([start_apps/1, start_apps/2, stop_apps/1]).
30-export([product_info/0,
31         product_name/0,
32         product_version/0,
33         base_product_name/0,
34         base_product_version/0,
35         motd_file/0,
36         motd/0]).
37%% For CLI, testing and mgmt-agent.
38-export([set_log_level/1, log_locations/0, config_files/0]).
39-export([is_booted/1, is_booted/0, is_booting/1, is_booting/0]).
40
41%%---------------------------------------------------------------------------
42%% Boot steps.
43-export([maybe_insert_default_data/0, boot_delegate/0, recover/0]).
44
45%% for tests
46-export([validate_msg_store_io_batch_size_and_credit_disc_bound/2]).
47
48-rabbit_boot_step({pre_boot, [{description, "rabbit boot start"}]}).
49
50-rabbit_boot_step({codec_correctness_check,
51                   [{description, "codec correctness check"},
52                    {mfa,         {rabbit_binary_generator,
53                                   check_empty_frame_size,
54                                   []}},
55                    {requires,    pre_boot},
56                    {enables,     external_infrastructure}]}).
57
58%% rabbit_alarm currently starts memory and disk space monitors
59-rabbit_boot_step({rabbit_alarm,
60                   [{description, "alarm handler"},
61                    {mfa,         {rabbit_alarm, start, []}},
62                    {requires,    pre_boot},
63                    {enables,     external_infrastructure}]}).
64
65-rabbit_boot_step({feature_flags,
66                   [{description, "feature flags registry and initial state"},
67                    {mfa,         {rabbit_feature_flags, init, []}},
68                    {requires,    pre_boot},
69                    {enables,     external_infrastructure}]}).
70
71-rabbit_boot_step({database,
72                   [{mfa,         {rabbit_mnesia, init, []}},
73                    {requires,    file_handle_cache},
74                    {enables,     external_infrastructure}]}).
75
76-rabbit_boot_step({database_sync,
77                   [{description, "database sync"},
78                    {mfa,         {rabbit_sup, start_child, [mnesia_sync]}},
79                    {requires,    database},
80                    {enables,     external_infrastructure}]}).
81
82-rabbit_boot_step({code_server_cache,
83                   [{description, "code_server cache server"},
84                    {mfa,         {rabbit_sup, start_child, [code_server_cache]}},
85                    {requires,    rabbit_alarm},
86                    {enables,     file_handle_cache}]}).
87
88-rabbit_boot_step({file_handle_cache,
89                   [{description, "file handle cache server"},
90                    {mfa,         {rabbit, start_fhc, []}},
91                    %% FHC needs memory monitor to be running
92                    {requires,    code_server_cache},
93                    {enables,     worker_pool}]}).
94
95-rabbit_boot_step({worker_pool,
96                   [{description, "default worker pool"},
97                    {mfa,         {rabbit_sup, start_supervisor_child,
98                                   [worker_pool_sup]}},
99                    {requires,    pre_boot},
100                    {enables,     external_infrastructure}]}).
101
102-rabbit_boot_step({definition_import_worker_pool,
103                   [{description, "dedicated worker pool for definition import"},
104                    {mfa,         {rabbit_definitions, boot, []}},
105                    {requires,    external_infrastructure}]}).
106
107-rabbit_boot_step({external_infrastructure,
108                   [{description, "external infrastructure ready"}]}).
109
110-rabbit_boot_step({rabbit_registry,
111                   [{description, "plugin registry"},
112                    {mfa,         {rabbit_sup, start_child,
113                                   [rabbit_registry]}},
114                    {requires,    external_infrastructure},
115                    {enables,     kernel_ready}]}).
116
117-rabbit_boot_step({rabbit_core_metrics,
118                   [{description, "core metrics storage"},
119                    {mfa,         {rabbit_sup, start_child,
120                                   [rabbit_metrics]}},
121                    {requires,    pre_boot},
122                    {enables,     external_infrastructure}]}).
123
124-rabbit_boot_step({rabbit_osiris_metrics,
125                   [{description, "osiris metrics scraper"},
126                    {mfa,         {rabbit_sup, start_child,
127                                   [rabbit_osiris_metrics]}},
128                    {requires,    pre_boot},
129                    {enables,     external_infrastructure}]}).
130
131-rabbit_boot_step({rabbit_global_counters,
132                   [{description, "global counters"},
133                    {mfa,         {rabbit_global_counters, boot_step,
134                                   []}},
135                    {requires,    pre_boot},
136                    {enables,     external_infrastructure}]}).
137
138-rabbit_boot_step({rabbit_event,
139                   [{description, "statistics event manager"},
140                    {mfa,         {rabbit_sup, start_restartable_child,
141                                   [rabbit_event]}},
142                    {requires,    external_infrastructure},
143                    {enables,     kernel_ready}]}).
144
145-rabbit_boot_step({kernel_ready,
146                   [{description, "kernel ready"},
147                    {requires,    external_infrastructure}]}).
148
149-rabbit_boot_step({rabbit_memory_monitor,
150                   [{description, "memory monitor"},
151                    {mfa,         {rabbit_sup, start_restartable_child,
152                                   [rabbit_memory_monitor]}},
153                    {requires,    rabbit_alarm},
154                    {enables,     core_initialized}]}).
155
156-rabbit_boot_step({guid_generator,
157                   [{description, "guid generator"},
158                    {mfa,         {rabbit_sup, start_restartable_child,
159                                   [rabbit_guid]}},
160                    {requires,    kernel_ready},
161                    {enables,     core_initialized}]}).
162
163-rabbit_boot_step({delegate_sup,
164                   [{description, "cluster delegate"},
165                    {mfa,         {rabbit, boot_delegate, []}},
166                    {requires,    kernel_ready},
167                    {enables,     core_initialized}]}).
168
169-rabbit_boot_step({rabbit_node_monitor,
170                   [{description, "node monitor"},
171                    {mfa,         {rabbit_sup, start_restartable_child,
172                                   [rabbit_node_monitor]}},
173                    {requires,    [rabbit_alarm, guid_generator]},
174                    {enables,     core_initialized}]}).
175
176-rabbit_boot_step({rabbit_epmd_monitor,
177                   [{description, "epmd monitor"},
178                    {mfa,         {rabbit_sup, start_restartable_child,
179                                   [rabbit_epmd_monitor]}},
180                    {requires,    kernel_ready},
181                    {enables,     core_initialized}]}).
182
183-rabbit_boot_step({rabbit_sysmon_minder,
184                   [{description, "sysmon_handler supervisor"},
185                    {mfa,         {rabbit_sup, start_restartable_child,
186                                   [rabbit_sysmon_minder]}},
187                    {requires,    kernel_ready},
188                    {enables,     core_initialized}]}).
189
190-rabbit_boot_step({core_initialized,
191                   [{description, "core initialized"},
192                    {requires,    kernel_ready}]}).
193
194-rabbit_boot_step({upgrade_queues,
195                   [{description, "per-vhost message store migration"},
196                    {mfa,         {rabbit_upgrade,
197                                   maybe_migrate_queues_to_per_vhost_storage,
198                                   []}},
199                    {requires,    [core_initialized]},
200                    {enables,     recovery}]}).
201
202-rabbit_boot_step({recovery,
203                   [{description, "exchange, queue and binding recovery"},
204                    {mfa,         {rabbit, recover, []}},
205                    {requires,    [core_initialized]},
206                    {enables,     routing_ready}]}).
207
208-rabbit_boot_step({empty_db_check,
209                   [{description, "empty DB check"},
210                    {mfa,         {?MODULE, maybe_insert_default_data, []}},
211                    {requires,    recovery},
212                    {enables,     routing_ready}]}).
213
214-rabbit_boot_step({routing_ready,
215                   [{description, "message delivery logic ready"},
216                    {requires,    [core_initialized, recovery]}]}).
217
218-rabbit_boot_step({connection_tracking,
219                   [{description, "connection tracking infrastructure"},
220                    {mfa,         {rabbit_connection_tracking, boot, []}},
221                    {enables,     routing_ready}]}).
222
223-rabbit_boot_step({channel_tracking,
224                   [{description, "channel tracking infrastructure"},
225                    {mfa,         {rabbit_channel_tracking, boot, []}},
226                    {enables,     routing_ready}]}).
227
228-rabbit_boot_step({background_gc,
229                   [{description, "background garbage collection"},
230                    {mfa,         {rabbit_sup, start_restartable_child,
231                                   [background_gc]}},
232                    {requires,    [core_initialized, recovery]},
233                    {enables,     routing_ready}]}).
234
235-rabbit_boot_step({rabbit_core_metrics_gc,
236                   [{description, "background core metrics garbage collection"},
237                    {mfa,         {rabbit_sup, start_restartable_child,
238                                   [rabbit_core_metrics_gc]}},
239                    {requires,    [core_initialized, recovery]},
240                    {enables,     routing_ready}]}).
241
242-rabbit_boot_step({rabbit_looking_glass,
243                   [{description, "Looking Glass tracer and profiler"},
244                    {mfa,         {rabbit_looking_glass, boot, []}},
245                    {requires,    [core_initialized, recovery]},
246                    {enables,     routing_ready}]}).
247
248-rabbit_boot_step({pre_flight,
249                   [{description, "ready to communicate with peers and clients"},
250                    {requires,    [core_initialized, recovery, routing_ready]}]}).
251
252-rabbit_boot_step({cluster_name,
253                   [{description, "sets cluster name if configured"},
254                    {mfa,         {rabbit_nodes, boot, []}},
255                    {requires,    pre_flight}
256                    ]}).
257
258-rabbit_boot_step({direct_client,
259                   [{description, "direct client"},
260                    {mfa,         {rabbit_direct, boot, []}},
261                    {requires,    pre_flight}
262                    ]}).
263
264-rabbit_boot_step({notify_cluster,
265                   [{description, "notifies cluster peers of our presence"},
266                    {mfa,         {rabbit_node_monitor, notify_node_up, []}},
267                    {requires,    pre_flight}]}).
268
269-rabbit_boot_step({networking,
270                   [{description, "TCP and TLS listeners (backwards compatibility)"},
271                    {mfa,         {logger, debug, ["'networking' boot step skipped and moved to end of startup", [], #{domain => ?RMQLOG_DOMAIN_GLOBAL}]}},
272                    {requires,    notify_cluster}]}).
273
274%%---------------------------------------------------------------------------
275
276-include_lib("rabbit_common/include/rabbit_framing.hrl").
277-include_lib("rabbit_common/include/rabbit.hrl").
278
279-define(APPS, [os_mon, mnesia, rabbit_common, rabbitmq_prelaunch, ra, sysmon_handler, rabbit, osiris]).
280
281-define(DIRTY_IO_SCHEDULERS_WARNING_THRESHOLD, 10).
282
283%% 1 minute
284-define(BOOT_START_TIMEOUT,     1 * 60 * 1000).
285%% 12 hours
286-define(BOOT_FINISH_TIMEOUT,    12 * 60 * 60 * 1000).
287%% 100 ms
288-define(BOOT_STATUS_CHECK_INTERVAL, 100).
289
290-define(COORD_WAL_MAX_SIZE_B, 64_000_000).
291
292%%----------------------------------------------------------------------------
293
294-type restart_type() :: 'permanent' | 'transient' | 'temporary'.
295
296-type param() :: atom().
297-type app_name() :: atom().
298
299%%----------------------------------------------------------------------------
300
301-spec start() -> 'ok'.
302
303start() ->
304    %% start() vs. boot(): we want to throw an error in start().
305    start_it(temporary).
306
307-spec boot() -> 'ok'.
308
309boot() ->
310    %% start() vs. boot(): we want the node to exit in boot(). Because
311    %% applications are started with `transient`, any error during their
312    %% startup will abort the node.
313    start_it(transient).
314
315run_prelaunch_second_phase() ->
316    %% Finish the prelaunch phase started by the `rabbitmq_prelaunch`
317    %% application.
318    %%
319    %% The first phase was handled by the `rabbitmq_prelaunch`
320    %% application. It was started in one of the following way:
321    %%   - from an Erlang release boot script;
322    %%   - from the rabbit:boot/0 or rabbit:start/0 functions.
323    %%
324    %% The `rabbitmq_prelaunch` application creates the context map from
325    %% the environment and the configuration files early during Erlang
326    %% VM startup. Once it is done, all application environments are
327    %% configured (in particular `mnesia` and `ra`).
328    %%
329    %% This second phase depends on other modules & facilities of
330    %% RabbitMQ core. That's why we need to run it now, from the
331    %% `rabbit` application start function.
332
333    %% We assert Mnesia is stopped before we run the prelaunch
334    %% phases. See `rabbit_prelaunch` for an explanation.
335    %%
336    %% This is the second assertion, just in case Mnesia is started
337    %% between the two prelaunch phases.
338    rabbit_prelaunch:assert_mnesia_is_stopped(),
339
340    %% Get the context created by `rabbitmq_prelaunch` then proceed
341    %% with all steps in this phase.
342    #{initial_pass := IsInitialPass} =
343    Context = rabbit_prelaunch:get_context(),
344
345    case IsInitialPass of
346        true ->
347            ?LOG_DEBUG(""),
348            ?LOG_DEBUG(
349              "== Prelaunch phase [2/2] (initial pass) ==");
350        false ->
351            ?LOG_DEBUG(""),
352            ?LOG_DEBUG("== Prelaunch phase [2/2] =="),
353            ok
354    end,
355
356    %% 1. Enabled plugins file.
357    ok = rabbit_prelaunch_enabled_plugins_file:setup(Context),
358
359    %% 2. Feature flags registry.
360    ok = rabbit_prelaunch_feature_flags:setup(Context),
361
362    %% 3. Logging.
363    ok = rabbit_prelaunch_logging:setup(Context),
364
365    %% 4. Clustering.
366    ok = rabbit_prelaunch_cluster:setup(Context),
367
368    %% Start Mnesia now that everything is ready.
369    ?LOG_DEBUG("Starting Mnesia"),
370    ok = mnesia:start(),
371
372    ?LOG_DEBUG(""),
373    ?LOG_DEBUG("== Prelaunch DONE =="),
374
375    ?LOG_DEBUG("Starting Ra Systems"),
376    Default = ra_system:default_config(),
377    Quorum = Default#{name => quorum_queues},
378                      % names => ra_system:derive_names(quorum)},
379    CoordDataDir = filename:join([rabbit_mnesia:dir(), "coordination", node()]),
380    Coord = Default#{name => coordination,
381                     data_dir => CoordDataDir,
382                     wal_data_dir => CoordDataDir,
383                     wal_max_size_bytes => ?COORD_WAL_MAX_SIZE_B,
384                     names => ra_system:derive_names(coordination)},
385
386    {ok, _} = ra_system:start(Quorum),
387    {ok, _} = ra_system:start(Coord),
388
389    ?LOG_DEBUG(""),
390    ?LOG_DEBUG("== Ra System Start done DONE =="),
391
392    case IsInitialPass of
393        true  -> rabbit_prelaunch:initial_pass_finished();
394        false -> ok
395    end,
396    ok.
397
398start_it(StartType) ->
399    case spawn_boot_marker() of
400        {ok, Marker} ->
401            T0 = erlang:timestamp(),
402            ?LOG_INFO("RabbitMQ is asked to start...", [],
403                      #{domain => ?RMQLOG_DOMAIN_PRELAUNCH}),
404            try
405                {ok, _} = application:ensure_all_started(rabbitmq_prelaunch,
406                                                         StartType),
407                {ok, _} = application:ensure_all_started(rabbit,
408                                                         StartType),
409                ok = wait_for_ready_or_stopped(),
410
411                T1 = erlang:timestamp(),
412                ?LOG_DEBUG(
413                  "Time to start RabbitMQ: ~p µs",
414                  [timer:now_diff(T1, T0)]),
415                stop_boot_marker(Marker),
416                ok
417            catch
418                error:{badmatch, Error}:_ ->
419                    stop_boot_marker(Marker),
420                    case StartType of
421                        temporary -> throw(Error);
422                        _         -> exit(Error)
423                    end
424            end;
425        {already_booting, Marker} ->
426            stop_boot_marker(Marker),
427            ok
428    end.
429
430wait_for_ready_or_stopped() ->
431    ok = rabbit_boot_state:wait_for(ready, ?BOOT_FINISH_TIMEOUT),
432    case rabbit_boot_state:get() of
433        ready ->
434            ok;
435        _ ->
436            ok = rabbit_boot_state:wait_for(stopped, ?BOOT_FINISH_TIMEOUT),
437            rabbit_prelaunch:get_stop_reason()
438    end.
439
440spawn_boot_marker() ->
441    %% Compatibility with older RabbitMQ versions:
442    %% We register a process doing nothing to indicate that RabbitMQ is
443    %% booting. This is checked by `is_booting(Node)` on a remote node.
444    Marker = spawn_link(fun() -> receive stop -> ok end end),
445    case catch register(rabbit_boot, Marker) of
446        true -> {ok, Marker};
447        _    -> {already_booting, Marker}
448    end.
449
450stop_boot_marker(Marker) ->
451    unlink(Marker),
452    Marker ! stop,
453    ok.
454
455-spec stop() -> 'ok'.
456
457stop() ->
458    case wait_for_ready_or_stopped() of
459        ok ->
460            case rabbit_boot_state:get() of
461                ready ->
462                    Product = product_name(),
463                    ?LOG_INFO("~s is asked to stop...", [Product],
464                              #{domain => ?RMQLOG_DOMAIN_PRELAUNCH}),
465                    do_stop(),
466                    ?LOG_INFO(
467                      "Successfully stopped ~s and its dependencies",
468                      [Product],
469                      #{domain => ?RMQLOG_DOMAIN_PRELAUNCH}),
470                    ok;
471                stopped ->
472                    ok
473            end;
474        _ ->
475            ok
476    end.
477
478do_stop() ->
479    Apps0 = ?APPS ++ rabbit_plugins:active(),
480    %% We ensure that Mnesia is stopped last (or more exactly, after rabbit).
481    Apps1 = app_utils:app_dependency_order(Apps0, true) -- [mnesia],
482    Apps = [mnesia | Apps1],
483    %% this will also perform unregistration with the peer discovery backend
484    %% as needed
485    stop_apps(Apps).
486
487-spec stop_and_halt() -> no_return().
488
489stop_and_halt() ->
490    try
491        stop()
492    catch Type:Reason ->
493        ?LOG_ERROR(
494          "Error trying to stop ~s: ~p:~p",
495          [product_name(), Type, Reason],
496          #{domain => ?RMQLOG_DOMAIN_PRELAUNCH}),
497        error({Type, Reason})
498    after
499        %% Enclose all the logging in the try block.
500        %% init:stop() will be called regardless of any errors.
501        try
502            AppsLeft = [ A || {A, _, _} <- application:which_applications() ],
503            ?LOG_ERROR(
504                lists:flatten(
505                  ["Halting Erlang VM with the following applications:~n",
506                   ["    ~p~n" || _ <- AppsLeft]]),
507                AppsLeft,
508                #{domain => ?RMQLOG_DOMAIN_GLOBAL}),
509            %% Also duplicate this information to stderr, so console where
510            %% foreground broker was running (or systemd journal) will
511            %% contain information about graceful termination.
512            io:format(standard_error, "Gracefully halting Erlang VM~n", [])
513        after
514            init:stop()
515        end
516    end,
517    ok.
518
519-spec start_apps([app_name()]) -> 'ok'.
520
521start_apps(Apps) ->
522    start_apps(Apps, #{}).
523
524-spec start_apps([app_name()],
525                 #{app_name() => restart_type()}) -> 'ok'.
526
527%% TODO: start_apps/2 and is now specific to plugins. This function
528%% should be moved over `rabbit_plugins', along with stop_apps/1, once
529%% the latter stops using app_utils as well.
530
531start_apps(Apps, RestartTypes) ->
532    false = lists:member(rabbit, Apps), %% Assertion.
533    %% We need to load all applications involved in order to be able to
534    %% find new feature flags.
535    app_utils:load_applications(Apps),
536    ok = rabbit_feature_flags:refresh_feature_flags_after_app_load(Apps),
537    rabbit_prelaunch_conf:decrypt_config(Apps),
538    lists:foreach(
539      fun(App) ->
540              RestartType = maps:get(App, RestartTypes, temporary),
541              ok = rabbit_boot_steps:run_boot_steps([App]),
542              case application:ensure_all_started(App, RestartType) of
543                  {ok, _}         -> ok;
544                  {error, Reason} -> throw({could_not_start, App, Reason})
545              end
546      end, Apps).
547
548-spec stop_apps([app_name()]) -> 'ok'.
549
550stop_apps([]) ->
551    ok;
552stop_apps(Apps) ->
553    ?LOG_INFO(
554        lists:flatten(
555          ["Stopping ~s applications and their dependencies in the following order:~n",
556           ["    ~p~n" || _ <- Apps]]),
557        [product_name() | lists:reverse(Apps)],
558        #{domain => ?RMQLOG_DOMAIN_PRELAUNCH}),
559    ok = app_utils:stop_applications(
560           Apps, handle_app_error(error_during_shutdown)),
561    case lists:member(rabbit, Apps) of
562        %% plugin deactivation
563        false -> rabbit_boot_steps:run_cleanup_steps(Apps);
564        true  -> ok %% it's all going anyway
565    end,
566    ok.
567
568-spec handle_app_error(_) -> fun((_, _) -> no_return()).
569handle_app_error(Term) ->
570    fun(App, {bad_return, {_MFA, {'EXIT', ExitReason}}}) ->
571            throw({Term, App, ExitReason});
572       (App, Reason) ->
573            throw({Term, App, Reason})
574    end.
575
576is_booting() -> is_booting(node()).
577
578is_booting(Node) when Node =:= node() ->
579    rabbit_boot_state:has_reached_and_is_active(booting)
580    andalso
581    not rabbit_boot_state:has_reached(ready);
582is_booting(Node) ->
583    case rpc:call(Node, rabbit, is_booting, []) of
584        {badrpc, _} = Err -> Err;
585        Ret               -> Ret
586    end.
587
588
589-spec await_startup() -> 'ok' | {'error', 'timeout'}.
590
591await_startup() ->
592    await_startup(node(), false).
593
594-spec await_startup(node() | non_neg_integer()) -> 'ok' | {'error', 'timeout'}.
595
596await_startup(Node) when is_atom(Node) ->
597    await_startup(Node, false);
598  await_startup(Timeout) when is_integer(Timeout) ->
599      await_startup(node(), false, Timeout).
600
601-spec await_startup(node(), boolean()) -> 'ok'  | {'error', 'timeout'}.
602
603await_startup(Node, PrintProgressReports) ->
604    case is_booting(Node) of
605        true  -> wait_for_boot_to_finish(Node, PrintProgressReports);
606        false ->
607            case is_running(Node) of
608                true  -> ok;
609                false -> wait_for_boot_to_start(Node),
610                         wait_for_boot_to_finish(Node, PrintProgressReports)
611            end
612    end.
613
614-spec await_startup(node(), boolean(), non_neg_integer()) -> 'ok'  | {'error', 'timeout'}.
615
616await_startup(Node, PrintProgressReports, Timeout) ->
617    case is_booting(Node) of
618        true  -> wait_for_boot_to_finish(Node, PrintProgressReports, Timeout);
619        false ->
620            case is_running(Node) of
621                true  -> ok;
622                false -> wait_for_boot_to_start(Node, Timeout),
623                         wait_for_boot_to_finish(Node, PrintProgressReports, Timeout)
624            end
625    end.
626
627wait_for_boot_to_start(Node) ->
628    wait_for_boot_to_start(Node, ?BOOT_START_TIMEOUT).
629
630wait_for_boot_to_start(Node, infinity) ->
631    %% This assumes that 100K iterations is close enough to "infinity".
632    %% Now that's deep.
633    do_wait_for_boot_to_start(Node, 100000);
634wait_for_boot_to_start(Node, Timeout) ->
635    Iterations = Timeout div ?BOOT_STATUS_CHECK_INTERVAL,
636    do_wait_for_boot_to_start(Node, Iterations).
637
638do_wait_for_boot_to_start(_Node, IterationsLeft) when IterationsLeft =< 0 ->
639    {error, timeout};
640do_wait_for_boot_to_start(Node, IterationsLeft) ->
641    case is_booting(Node) of
642        false ->
643            timer:sleep(?BOOT_STATUS_CHECK_INTERVAL),
644            do_wait_for_boot_to_start(Node, IterationsLeft - 1);
645        {badrpc, _} = Err ->
646            Err;
647        true  ->
648            ok
649    end.
650
651wait_for_boot_to_finish(Node, PrintProgressReports) ->
652    wait_for_boot_to_finish(Node, PrintProgressReports, ?BOOT_FINISH_TIMEOUT).
653
654wait_for_boot_to_finish(Node, PrintProgressReports, infinity) ->
655    %% This assumes that 100K iterations is close enough to "infinity".
656    %% Now that's deep.
657    do_wait_for_boot_to_finish(Node, PrintProgressReports, 100000);
658wait_for_boot_to_finish(Node, PrintProgressReports, Timeout) ->
659    Iterations = Timeout div ?BOOT_STATUS_CHECK_INTERVAL,
660    do_wait_for_boot_to_finish(Node, PrintProgressReports, Iterations).
661
662do_wait_for_boot_to_finish(_Node, _PrintProgressReports, IterationsLeft) when IterationsLeft =< 0 ->
663    {error, timeout};
664do_wait_for_boot_to_finish(Node, PrintProgressReports, IterationsLeft) ->
665    case is_booting(Node) of
666        false ->
667            %% We don't want badrpc error to be interpreted as false,
668            %% so we don't call rabbit:is_running(Node)
669            case rpc:call(Node, rabbit, is_running, []) of
670                true              -> ok;
671                false             -> {error, rabbit_is_not_running};
672                {badrpc, _} = Err -> Err
673            end;
674        {badrpc, _} = Err ->
675            Err;
676        true  ->
677            maybe_print_boot_progress(PrintProgressReports, IterationsLeft),
678            timer:sleep(?BOOT_STATUS_CHECK_INTERVAL),
679            do_wait_for_boot_to_finish(Node, PrintProgressReports, IterationsLeft - 1)
680    end.
681
682maybe_print_boot_progress(false = _PrintProgressReports, _IterationsLeft) ->
683  ok;
684maybe_print_boot_progress(true, IterationsLeft) ->
685  case IterationsLeft rem 100 of
686    %% This will be printed on the CLI command end to illustrate some
687    %% progress.
688    0 -> io:format("Still booting, will check again in 10 seconds...~n");
689    _ -> ok
690  end.
691
692-spec status
693        () -> [{pid, integer()} |
694               {running_applications, [{atom(), string(), string()}]} |
695               {os, {atom(), atom()}} |
696               {erlang_version, string()} |
697               {memory, any()}].
698
699status() ->
700    Version = base_product_version(),
701    S1 = [{pid,                  list_to_integer(os:getpid())},
702          %% The timeout value used is twice that of gen_server:call/2.
703          {running_applications, rabbit_misc:which_applications()},
704          {os,                   os:type()},
705          {rabbitmq_version,     Version},
706          {erlang_version,       erlang:system_info(system_version)},
707          {memory,               rabbit_vm:memory()},
708          {alarms,               alarms()},
709          {is_under_maintenance, rabbit_maintenance:is_being_drained_local_read(node())},
710          {listeners,            listeners()},
711          {vm_memory_calculation_strategy, vm_memory_monitor:get_memory_calculation_strategy()}],
712    S2 = rabbit_misc:filter_exit_map(
713           fun ({Key, {M, F, A}}) -> {Key, erlang:apply(M, F, A)} end,
714           [{vm_memory_high_watermark, {vm_memory_monitor,
715                                        get_vm_memory_high_watermark, []}},
716            {vm_memory_limit,          {vm_memory_monitor,
717                                        get_memory_limit, []}},
718            {disk_free_limit,          {rabbit_disk_monitor,
719                                        get_disk_free_limit, []}},
720            {disk_free,                {rabbit_disk_monitor,
721                                        get_disk_free, []}}]),
722    S3 = rabbit_misc:with_exit_handler(
723           fun () -> [] end,
724           fun () -> [{file_descriptors, file_handle_cache:info()}] end),
725    S4 = [{processes,        [{limit, erlang:system_info(process_limit)},
726                              {used, erlang:system_info(process_count)}]},
727          {run_queue,        erlang:statistics(run_queue)},
728          {uptime,           begin
729                                 {T,_} = erlang:statistics(wall_clock),
730                                 T div 1000
731                             end},
732          {kernel,           {net_ticktime, net_kernel:get_net_ticktime()}}],
733    S5 = [{active_plugins, rabbit_plugins:active()},
734          {enabled_plugin_file, rabbit_plugins:enabled_plugins_file()}],
735    S6 = [{config_files, config_files()},
736           {log_files, log_locations()},
737           {data_directory, rabbit_mnesia:dir()},
738           {raft_data_directory, ra_env:data_dir()}],
739    Totals = case is_running() of
740                 true ->
741                     [{virtual_host_count, rabbit_vhost:count()},
742                      {connection_count,
743                       length(rabbit_networking:connections_local())},
744                      {queue_count, total_queue_count()}];
745                 false ->
746                     []
747             end,
748    S7 = [{totals, Totals}],
749    S8 = lists:filter(
750           fun
751               ({product_base_name, _}) -> true;
752               ({product_base_version, _}) -> true;
753               ({product_name, _}) -> true;
754               ({product_version, _}) -> true;
755               (_) -> false
756           end,
757           maps:to_list(product_info())),
758    S1 ++ S2 ++ S3 ++ S4 ++ S5 ++ S6 ++ S7 ++ S8.
759
760alarms() ->
761    Alarms = rabbit_misc:with_exit_handler(rabbit_misc:const([]),
762                                           fun rabbit_alarm:get_alarms/0),
763    N = node(),
764    %% [{{resource_limit,memory,rabbit@mercurio},[]}]
765    [{resource_limit, Limit, Node} || {{resource_limit, Limit, Node}, _} <- Alarms, Node =:= N].
766
767listeners() ->
768    Listeners = try
769                    rabbit_networking:active_listeners()
770                catch
771                    exit:{aborted, _} -> []
772                end,
773    [L || L = #listener{node = Node} <- Listeners, Node =:= node()].
774
775total_queue_count() ->
776    lists:foldl(fun (VirtualHost, Acc) ->
777                  Acc + rabbit_amqqueue:count(VirtualHost)
778                end,
779                0, rabbit_vhost:list_names()).
780
781-spec is_running() -> boolean().
782
783is_running() -> is_running(node()).
784
785-spec is_running(node()) -> boolean().
786
787is_running(Node) when Node =:= node() ->
788    case rabbit_boot_state:get() of
789        ready       -> true;
790        _           -> false
791    end;
792is_running(Node) ->
793    case rpc:call(Node, rabbit, is_running, []) of
794        true -> true;
795        _    -> false
796    end.
797
798is_booted() -> is_booted(node()).
799
800is_booted(Node) ->
801    case is_booting(Node) of
802        false ->
803            is_running(Node);
804        _ -> false
805    end.
806
807-spec environment() -> [{param(), term()}].
808
809environment() ->
810    %% The timeout value is twice that of gen_server:call/2.
811    [{A, environment(A)} ||
812        {A, _, _} <- lists:keysort(1, application:which_applications(10000))].
813
814environment(App) ->
815    Ignore = [default_pass, included_applications],
816    lists:keysort(1, [P || P = {K, _} <- application:get_all_env(App),
817                           not lists:member(K, Ignore)]).
818
819-spec rotate_logs() -> rabbit_types:ok_or_error(any()).
820
821rotate_logs() ->
822    ?LOG_ERROR(
823       "Forcing log rotation is currently unsupported",
824       #{domain => ?RMQLOG_DOMAIN_GLOBAL}),
825    {error, unsupported}.
826
827%%--------------------------------------------------------------------
828
829-spec start('normal',[]) ->
830          {'error',
831           {'erlang_version_too_old',
832            {'found',string(),string()},
833            {'required',string(),string()}}} |
834          {'ok',pid()}.
835
836start(normal, []) ->
837    %% Reset boot state and clear the stop reason again (it was already
838    %% made in rabbitmq_prelaunch).
839    %%
840    %% This is important if the previous startup attempt failed after
841    %% rabbitmq_prelaunch was started and the application is still
842    %% running.
843    rabbit_boot_state:set(booting),
844    rabbit_prelaunch:clear_stop_reason(),
845
846    try
847        run_prelaunch_second_phase(),
848
849        ProductInfo = product_info(),
850        case ProductInfo of
851            #{product_overridden := true,
852              product_base_name := BaseName,
853              product_base_version := BaseVersion} ->
854                ?LOG_INFO(
855                   "~n Starting ~s ~s on Erlang ~s [~s]~n Based on ~s ~s~n ~s~n ~s",
856                   [product_name(), product_version(), rabbit_misc:otp_release(),
857                    emu_flavor(),
858                    BaseName, BaseVersion,
859                    ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE],
860                   #{domain => ?RMQLOG_DOMAIN_PRELAUNCH});
861            _ ->
862                ?LOG_INFO(
863                   "~n Starting ~s ~s on Erlang ~s [~s]~n ~s~n ~s",
864                   [product_name(), product_version(), rabbit_misc:otp_release(),
865                    emu_flavor(),
866                    ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE],
867                   #{domain => ?RMQLOG_DOMAIN_PRELAUNCH})
868        end,
869        log_motd(),
870        {ok, SupPid} = rabbit_sup:start_link(),
871
872        %% Compatibility with older RabbitMQ versions + required by
873        %% rabbit_node_monitor:notify_node_up/0:
874        %%
875        %% We register the app process under the name `rabbit`. This is
876        %% checked by `is_running(Node)` on a remote node. The process
877        %% is also monitord by rabbit_node_monitor.
878        %%
879        %% The process name must be registered *before* running the boot
880        %% steps: that's when rabbit_node_monitor will set the process
881        %% monitor up.
882        %%
883        %% Note that plugins were not taken care of at this point
884        %% either.
885        ?LOG_DEBUG(
886          "Register `rabbit` process (~p) for rabbit_node_monitor",
887          [self()]),
888        true = register(rabbit, self()),
889
890        print_banner(),
891        log_banner(),
892        warn_if_kernel_config_dubious(),
893        warn_if_disc_io_options_dubious(),
894
895        ?LOG_DEBUG(""),
896        ?LOG_DEBUG("== Plugins (prelaunch phase) =="),
897
898        ?LOG_DEBUG("Setting plugins up"),
899        %% `Plugins` contains all the enabled plugins, plus their
900        %% dependencies. The order is important: dependencies appear
901        %% before plugin which depend on them.
902        Plugins = rabbit_plugins:setup(),
903        ?LOG_DEBUG(
904          "Loading the following plugins: ~p", [Plugins]),
905        %% We can load all plugins and refresh their feature flags at
906        %% once, because it does not involve running code from the
907        %% plugins.
908        ok = app_utils:load_applications(Plugins),
909        ok = rabbit_feature_flags:refresh_feature_flags_after_app_load(
910               Plugins),
911
912        ?LOG_DEBUG(""),
913        ?LOG_DEBUG("== Boot steps =="),
914
915        ok = rabbit_boot_steps:run_boot_steps([rabbit | Plugins]),
916        rabbit_boot_state:set(core_started),
917        run_postlaunch_phase(Plugins),
918        {ok, SupPid}
919    catch
920        throw:{error, _} = Error ->
921            mnesia:stop(),
922            rabbit_prelaunch_errors:log_error(Error),
923            rabbit_prelaunch:set_stop_reason(Error),
924            rabbit_boot_state:set(stopped),
925            Error;
926        Class:Exception:Stacktrace ->
927            mnesia:stop(),
928            rabbit_prelaunch_errors:log_exception(
929              Class, Exception, Stacktrace),
930            Error = {error, Exception},
931            rabbit_prelaunch:set_stop_reason(Error),
932            rabbit_boot_state:set(stopped),
933            Error
934    end.
935
936run_postlaunch_phase(Plugins) ->
937    spawn(fun() -> do_run_postlaunch_phase(Plugins) end).
938
939do_run_postlaunch_phase(Plugins) ->
940    %% Once RabbitMQ itself is started, we need to run a few more steps,
941    %% in particular start plugins.
942    ?LOG_DEBUG(""),
943    ?LOG_DEBUG("== Postlaunch phase =="),
944
945    try
946        %% Successful boot resets node maintenance state.
947        ?LOG_DEBUG(""),
948        ?LOG_INFO("Resetting node maintenance status"),
949        _ = rabbit_maintenance:unmark_as_being_drained(),
950
951        ?LOG_DEBUG(""),
952        ?LOG_DEBUG("== Plugins (postlaunch phase) =="),
953
954        %% However, we want to run their boot steps and actually start
955        %% them one by one, to ensure a dependency is fully started
956        %% before a plugin which depends on it gets a chance to start.
957        ?LOG_DEBUG("Starting the following plugins: ~p", [Plugins]),
958        lists:foreach(
959          fun(Plugin) ->
960                  case application:ensure_all_started(Plugin) of
961                      {ok, _} -> ok;
962                      Error   -> throw(Error)
963                  end
964          end, Plugins),
965
966        %% Export definitions after all plugins have been enabled,
967        %% see rabbitmq/rabbitmq-server#2384.
968        case rabbit_definitions:maybe_load_definitions() of
969            ok           -> ok;
970            DefLoadError -> throw(DefLoadError)
971        end,
972
973        %% Start listeners after all plugins have been enabled,
974        %% see rabbitmq/rabbitmq-server#2405.
975        ?LOG_INFO("Ready to start client connection listeners"),
976        ok = rabbit_networking:boot(),
977
978        %% The node is ready: mark it as such and log it.
979        %% NOTE: PLEASE DO NOT ADD CRITICAL NODE STARTUP CODE AFTER THIS.
980        ActivePlugins = rabbit_plugins:active(),
981        StrictlyPlugins = rabbit_plugins:strictly_plugins(ActivePlugins),
982        ok = log_broker_started(StrictlyPlugins),
983
984        ?LOG_DEBUG("Marking ~s as running", [product_name()]),
985        rabbit_boot_state:set(ready)
986    catch
987        throw:{error, _} = Error ->
988            rabbit_prelaunch_errors:log_error(Error),
989            rabbit_prelaunch:set_stop_reason(Error),
990            do_stop();
991        Class:Exception:Stacktrace ->
992            rabbit_prelaunch_errors:log_exception(
993              Class, Exception, Stacktrace),
994            Error = {error, Exception},
995            rabbit_prelaunch:set_stop_reason(Error),
996            do_stop()
997    end.
998
999prep_stop(State) ->
1000    rabbit_boot_state:set(stopping),
1001    rabbit_peer_discovery:maybe_unregister(),
1002    State.
1003
1004-spec stop(_) -> 'ok'.
1005
1006stop(State) ->
1007    ok = rabbit_alarm:stop(),
1008    ok = case rabbit_mnesia:is_clustered() of
1009             true  -> ok;
1010             false -> rabbit_table:clear_ram_only_tables()
1011         end,
1012    case State of
1013        [] -> rabbit_prelaunch:set_stop_reason(normal);
1014        _  -> rabbit_prelaunch:set_stop_reason(State)
1015    end,
1016    rabbit_boot_state:set(stopped),
1017    ok.
1018
1019%%---------------------------------------------------------------------------
1020%% boot step functions
1021
1022-spec boot_delegate() -> 'ok'.
1023
1024boot_delegate() ->
1025    {ok, Count} = application:get_env(rabbit, delegate_count),
1026    rabbit_sup:start_supervisor_child(delegate_sup, [Count]).
1027
1028-spec recover() -> 'ok'.
1029
1030recover() ->
1031    ok = rabbit_policy:recover(),
1032    ok = rabbit_vhost:recover(),
1033    ok.
1034
1035-spec maybe_insert_default_data() -> 'ok'.
1036
1037maybe_insert_default_data() ->
1038    NoDefsToImport = not rabbit_definitions:has_configured_definitions_to_load(),
1039    case rabbit_table:needs_default_data() andalso NoDefsToImport of
1040        true  ->
1041            ?LOG_INFO("Will seed default virtual host and user...",
1042                      #{domain => ?RMQLOG_DOMAIN_GLOBAL}),
1043            insert_default_data();
1044        false ->
1045            ?LOG_INFO("Will not seed default virtual host and user: have definitions to load...",
1046                      #{domain => ?RMQLOG_DOMAIN_GLOBAL}),
1047            ok
1048    end.
1049
1050insert_default_data() ->
1051    DefaultUser = get_default_data_param(default_user),
1052    DefaultPass = get_default_data_param(default_pass),
1053    {ok, DefaultTags} = application:get_env(default_user_tags),
1054    DefaultVHost = get_default_data_param(default_vhost),
1055    {ok, [DefaultConfigurePerm, DefaultWritePerm, DefaultReadPerm]} =
1056        application:get_env(default_permissions),
1057
1058    DefaultUserBin = rabbit_data_coercion:to_binary(DefaultUser),
1059    DefaultPassBin = rabbit_data_coercion:to_binary(DefaultPass),
1060    DefaultVHostBin = rabbit_data_coercion:to_binary(DefaultVHost),
1061    DefaultConfigurePermBin = rabbit_data_coercion:to_binary(DefaultConfigurePerm),
1062    DefaultWritePermBin = rabbit_data_coercion:to_binary(DefaultWritePerm),
1063    DefaultReadPermBin = rabbit_data_coercion:to_binary(DefaultReadPerm),
1064
1065    ok = rabbit_vhost:add(DefaultVHostBin, <<"Default virtual host">>, [], ?INTERNAL_USER),
1066    ok = rabbit_auth_backend_internal:add_user(
1067        DefaultUserBin,
1068        DefaultPassBin,
1069        ?INTERNAL_USER
1070    ),
1071    ok = rabbit_auth_backend_internal:set_tags(DefaultUserBin, DefaultTags,
1072                                               ?INTERNAL_USER),
1073    ok = rabbit_auth_backend_internal:set_permissions(DefaultUserBin,
1074                                                      DefaultVHostBin,
1075                                                      DefaultConfigurePermBin,
1076                                                      DefaultWritePermBin,
1077                                                      DefaultReadPermBin,
1078                                                      ?INTERNAL_USER),
1079    ok.
1080
1081get_default_data_param(Param) ->
1082    #{var_origins := Origins} = Context = rabbit_prelaunch:get_context(),
1083    case maps:get(Param, Origins, default) of
1084        environment ->
1085            Value = maps:get(Param, Context),
1086            ?assert(is_binary(Value)),
1087            Value;
1088        default ->
1089            {ok, Value} = application:get_env(Param),
1090            Value
1091    end.
1092
1093%%---------------------------------------------------------------------------
1094%% logging
1095
1096-spec set_log_level(logger:level()) -> ok.
1097set_log_level(Level) ->
1098    rabbit_prelaunch_logging:set_log_level(Level).
1099
1100-spec log_locations() -> [rabbit_prelaunch_logging:log_location()].
1101log_locations() ->
1102    rabbit_prelaunch_logging:log_locations().
1103
1104-spec config_locations() -> [rabbit_config:config_location()].
1105config_locations() ->
1106    rabbit_config:config_files().
1107
1108-spec force_event_refresh(reference()) -> 'ok'.
1109
1110% Note: https://www.pivotaltracker.com/story/show/166962656
1111% This event is necessary for the stats timer to be initialized with
1112% the correct values once the management agent has started
1113force_event_refresh(Ref) ->
1114    % direct connections, e.g. MQTT, STOMP
1115    ok = rabbit_direct:force_event_refresh(Ref),
1116    % AMQP connections
1117    ok = rabbit_networking:force_connection_event_refresh(Ref),
1118    % "external" connections, which are not handled by the "AMQP core",
1119    % e.g. connections to the stream plugin
1120    ok = rabbit_networking:force_non_amqp_connection_event_refresh(Ref),
1121    ok = rabbit_channel:force_event_refresh(Ref),
1122    ok = rabbit_amqqueue:force_event_refresh(Ref).
1123
1124%%---------------------------------------------------------------------------
1125%% misc
1126
1127log_broker_started(Plugins) ->
1128    PluginList = iolist_to_binary([rabbit_misc:format(" * ~s~n", [P])
1129                                   || P <- Plugins]),
1130    Message = string:strip(rabbit_misc:format(
1131        "Server startup complete; ~b plugins started.~n~s",
1132        [length(Plugins), PluginList]), right, $\n),
1133    ?LOG_INFO(Message,
1134              #{domain => ?RMQLOG_DOMAIN_GLOBAL}),
1135    io:format(" completed with ~p plugins.~n", [length(Plugins)]).
1136
1137-define(RABBIT_TEXT_LOGO,
1138        "~n  ##  ##      ~s ~s"
1139        "~n  ##  ##"
1140        "~n  ##########  ~s"
1141        "~n  ######  ##"
1142        "~n  ##########  ~s").
1143-define(FG8_START,  "\033[38;5;202m").
1144-define(BG8_START,  "\033[48;5;202m").
1145-define(FG32_START, "\033[38;2;255;102;0m").
1146-define(BG32_START, "\033[48;2;255;102;0m").
1147-define(C_END,      "\033[0m").
1148-define(RABBIT_8BITCOLOR_LOGO,
1149        "~n  " ?BG8_START "  " ?C_END "  " ?BG8_START "  " ?C_END "      \033[1m" ?FG8_START "~s" ?C_END " ~s"
1150        "~n  " ?BG8_START "  " ?C_END "  " ?BG8_START "  " ?C_END
1151        "~n  " ?BG8_START "          " ?C_END "  ~s"
1152        "~n  " ?BG8_START "      " ?C_END "  " ?BG8_START "  " ?C_END
1153        "~n  " ?BG8_START "          " ?C_END "  ~s").
1154-define(RABBIT_32BITCOLOR_LOGO,
1155        "~n  " ?BG32_START "  " ?C_END "  " ?BG32_START "  " ?C_END "      \033[1m" ?FG32_START "~s" ?C_END " ~s"
1156        "~n  " ?BG32_START "  " ?C_END "  " ?BG32_START "  " ?C_END
1157        "~n  " ?BG32_START "          " ?C_END "  ~s"
1158        "~n  " ?BG32_START "      " ?C_END "  " ?BG32_START "  " ?C_END
1159        "~n  " ?BG32_START "          " ?C_END "  ~s").
1160
1161print_banner() ->
1162    Product = product_name(),
1163    Version = product_version(),
1164    LineListFormatter = fun (Placeholder, [_ | Tail] = LL) ->
1165                              LF = lists:flatten([Placeholder || _ <- lists:seq(1, length(Tail))]),
1166                              {LF, LL};
1167                            (_, []) ->
1168                              {"", ["(none)"]}
1169    end,
1170    Logo = case rabbit_prelaunch:get_context() of
1171               %% We use the colored logo only when running the
1172               %% interactive shell and when colors are supported.
1173               %%
1174               %% Basically it means it will be used on Unix when
1175               %% running "make run-broker" and that's about it.
1176               #{os_type := {unix, darwin},
1177                 interactive_shell := true,
1178                 output_supports_colors := true} -> ?RABBIT_8BITCOLOR_LOGO;
1179               #{interactive_shell := true,
1180                 output_supports_colors := true} -> ?RABBIT_32BITCOLOR_LOGO;
1181               _                                 -> ?RABBIT_TEXT_LOGO
1182           end,
1183    %% padded list lines
1184    {LogFmt, LogLocations} = LineListFormatter("~n        ~ts", log_locations()),
1185    {CfgFmt, CfgLocations} = LineListFormatter("~n                  ~ts", config_locations()),
1186    {MOTDFormat, MOTDArgs} = case motd() of
1187                                 undefined ->
1188                                     {"", []};
1189                                 MOTD ->
1190                                     Lines = string:split(MOTD, "\n", all),
1191                                     Padded = [case Line of
1192                                                   <<>> -> "\n";
1193                                                   _    -> ["  ", Line, "\n"]
1194                                               end
1195                                               || Line <- Lines],
1196                                     {"~n~ts", [Padded]}
1197                             end,
1198    io:format(Logo ++
1199              "~n" ++
1200              MOTDFormat ++
1201              "~n  Erlang:      ~ts [~ts]"
1202              "~n  TLS Library: ~ts"
1203              "~n"
1204              "~n  Doc guides:  https://rabbitmq.com/documentation.html"
1205              "~n  Support:     https://rabbitmq.com/contact.html"
1206              "~n  Tutorials:   https://rabbitmq.com/getstarted.html"
1207              "~n  Monitoring:  https://rabbitmq.com/monitoring.html"
1208              "~n"
1209              "~n  Logs: ~ts" ++ LogFmt ++ "~n"
1210              "~n  Config file(s): ~ts" ++ CfgFmt ++ "~n"
1211              "~n  Starting broker...",
1212              [Product, Version, ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE] ++
1213              [rabbit_misc:otp_release(), emu_flavor(), crypto_version()] ++
1214              MOTDArgs ++
1215              LogLocations ++
1216              CfgLocations).
1217
1218emu_flavor() ->
1219    %% emu_flavor was introduced in Erlang 24 so we need to catch the error on Erlang 23
1220    case catch(erlang:system_info(emu_flavor)) of
1221        {'EXIT', _} -> "emu";
1222        EmuFlavor -> EmuFlavor
1223    end.
1224
1225crypto_version() ->
1226    [{CryptoLibName, _, CryptoLibVersion}] = crypto:info_lib(),
1227    [CryptoLibName, " - ", CryptoLibVersion].
1228
1229log_motd() ->
1230    case motd() of
1231        undefined ->
1232            ok;
1233        MOTD ->
1234            Lines = string:split(MOTD, "\n", all),
1235            Padded = [case Line of
1236                          <<>> -> "\n";
1237                          _    -> [" ", Line, "\n"]
1238                      end
1239                      || Line <- Lines],
1240            ?LOG_INFO("~n~ts", [string:trim(Padded, trailing, [$\r, $\n])],
1241                      #{domain => ?RMQLOG_DOMAIN_GLOBAL})
1242    end.
1243
1244log_banner() ->
1245    {FirstLog, OtherLogs} = case log_locations() of
1246        [Head | Tail] ->
1247            {Head, [{"", F} || F <- Tail]};
1248        [] ->
1249            {"(none)", []}
1250    end,
1251    Settings = [{"node",           node()},
1252                {"home dir",       home_dir()},
1253                {"config file(s)", config_files()},
1254                {"cookie hash",    rabbit_nodes:cookie_hash()},
1255                {"log(s)",         FirstLog}] ++
1256               OtherLogs ++
1257               [{"database dir",   rabbit_mnesia:dir()}],
1258    DescrLen = 1 + lists:max([length(K) || {K, _V} <- Settings]),
1259    Format = fun (K, V) ->
1260                     rabbit_misc:format(
1261                       " ~-" ++ integer_to_list(DescrLen) ++ "s: ~ts~n", [K, V])
1262             end,
1263    Banner = string:strip(lists:flatten(
1264               [case S of
1265                    {"config file(s)" = K, []} ->
1266                        Format(K, "(none)");
1267                    {"config file(s)" = K, [V0 | Vs]} ->
1268                        [Format(K, V0) | [Format("", V) || V <- Vs]];
1269                    {K, V} ->
1270                        Format(K, V)
1271                end || S <- Settings]), right, $\n),
1272    ?LOG_INFO("~n~ts", [Banner],
1273              #{domain => ?RMQLOG_DOMAIN_GLOBAL}).
1274
1275warn_if_kernel_config_dubious() ->
1276    case os:type() of
1277        {win32, _} ->
1278            ok;
1279        _ ->
1280            case erlang:system_info(kernel_poll) of
1281                true  -> ok;
1282                false -> ?LOG_WARNING(
1283                           "Kernel poll (epoll, kqueue, etc) is disabled. "
1284                           "Throughput and CPU utilization may worsen.",
1285                           #{domain => ?RMQLOG_DOMAIN_GLOBAL})
1286            end
1287    end,
1288    DirtyIOSchedulers = erlang:system_info(dirty_io_schedulers),
1289    case DirtyIOSchedulers < ?DIRTY_IO_SCHEDULERS_WARNING_THRESHOLD of
1290        true  -> ?LOG_WARNING(
1291                   "Erlang VM is running with ~b dirty I/O schedulers, "
1292                   "file I/O performance may worsen", [DirtyIOSchedulers],
1293                   #{domain => ?RMQLOG_DOMAIN_GLOBAL});
1294        false -> ok
1295    end,
1296    IDCOpts = case application:get_env(kernel, inet_default_connect_options) of
1297                  undefined -> [];
1298                  {ok, Val} -> Val
1299              end,
1300    case proplists:get_value(nodelay, IDCOpts, false) of
1301        false -> ?LOG_WARNING("Nagle's algorithm is enabled for sockets, "
1302                              "network I/O latency will be higher",
1303                              #{domain => ?RMQLOG_DOMAIN_GLOBAL});
1304        true  -> ok
1305    end.
1306
1307warn_if_disc_io_options_dubious() ->
1308    %% if these values are not set, it doesn't matter since
1309    %% rabbit_variable_queue will pick up the values defined in the
1310    %% IO_BATCH_SIZE and CREDIT_DISC_BOUND constants.
1311    CreditDiscBound = rabbit_misc:get_env(rabbit, msg_store_credit_disc_bound,
1312                                          undefined),
1313    IoBatchSize = rabbit_misc:get_env(rabbit, msg_store_io_batch_size,
1314                                      undefined),
1315    case catch validate_msg_store_io_batch_size_and_credit_disc_bound(
1316                 CreditDiscBound, IoBatchSize) of
1317        ok -> ok;
1318        {error, {Reason, Vars}} ->
1319            ?LOG_WARNING(Reason, Vars,
1320                         #{domain => ?RMQLOG_DOMAIN_GLOBAL})
1321    end.
1322
1323validate_msg_store_io_batch_size_and_credit_disc_bound(CreditDiscBound,
1324                                                       IoBatchSize) ->
1325    case IoBatchSize of
1326        undefined ->
1327            ok;
1328        IoBatchSize when is_integer(IoBatchSize) ->
1329            if IoBatchSize < ?IO_BATCH_SIZE ->
1330                    throw({error,
1331                     {"io_batch_size of ~b lower than recommended value ~b, "
1332                      "paging performance may worsen",
1333                      [IoBatchSize, ?IO_BATCH_SIZE]}});
1334               true ->
1335                    ok
1336            end;
1337        IoBatchSize ->
1338            throw({error,
1339             {"io_batch_size should be an integer, but ~b given",
1340              [IoBatchSize]}})
1341    end,
1342
1343    %% CreditDiscBound = {InitialCredit, MoreCreditAfter}
1344    {RIC, RMCA} = ?CREDIT_DISC_BOUND,
1345    case CreditDiscBound of
1346        undefined ->
1347            ok;
1348        {IC, MCA} when is_integer(IC), is_integer(MCA) ->
1349            if IC < RIC; MCA < RMCA ->
1350                    throw({error,
1351                     {"msg_store_credit_disc_bound {~b, ~b} lower than"
1352                      "recommended value {~b, ~b},"
1353                      " paging performance may worsen",
1354                      [IC, MCA, RIC, RMCA]}});
1355               true ->
1356                    ok
1357            end;
1358        {IC, MCA} ->
1359            throw({error,
1360             {"both msg_store_credit_disc_bound values should be integers, but ~p given",
1361              [{IC, MCA}]}});
1362        CreditDiscBound ->
1363            throw({error,
1364             {"invalid msg_store_credit_disc_bound value given: ~p",
1365              [CreditDiscBound]}})
1366    end,
1367
1368    case {CreditDiscBound, IoBatchSize} of
1369        {undefined, undefined} ->
1370            ok;
1371        {_CDB, undefined} ->
1372            ok;
1373        {undefined, _IBS} ->
1374            ok;
1375        {{InitialCredit, _MCA}, IoBatchSize} ->
1376            if IoBatchSize < InitialCredit ->
1377                    throw(
1378                      {error,
1379                       {"msg_store_io_batch_size ~b should be bigger than the initial "
1380                        "credit value from msg_store_credit_disc_bound ~b,"
1381                        " paging performance may worsen",
1382                        [IoBatchSize, InitialCredit]}});
1383               true ->
1384                    ok
1385            end
1386    end.
1387
1388-spec product_name() -> string().
1389
1390product_name() ->
1391    case product_info() of
1392        #{product_name := ProductName}   -> ProductName;
1393        #{product_base_name := BaseName} -> BaseName
1394    end.
1395
1396-spec product_version() -> string().
1397
1398product_version() ->
1399    case product_info() of
1400        #{product_version := ProductVersion}   -> ProductVersion;
1401        #{product_base_version := BaseVersion} -> BaseVersion
1402    end.
1403
1404-spec product_info() -> #{product_base_name := string(),
1405                          product_base_version := string(),
1406                          product_overridden := boolean(),
1407                          product_name => string(),
1408                          product_version => string(),
1409                          otp_release := string()}.
1410
1411product_info() ->
1412    PTKey = {?MODULE, product},
1413    try
1414        %% The value is cached the first time to avoid calling the
1415        %% application master many times just for that.
1416        persistent_term:get(PTKey)
1417    catch
1418        error:badarg ->
1419            BaseName = base_product_name(),
1420            BaseVersion = base_product_version(),
1421            Info0 = #{product_base_name => BaseName,
1422                      product_base_version => BaseVersion,
1423                      otp_release => rabbit_misc:otp_release()},
1424
1425            {NameFromEnv, VersionFromEnv} =
1426            case rabbit_prelaunch:get_context() of
1427                #{product_name := NFE,
1428                  product_version := VFE} -> {NFE, VFE};
1429                _                         -> {undefined, undefined}
1430            end,
1431
1432            Info1 = case NameFromEnv of
1433                        undefined ->
1434                            NameFromApp = string_from_app_env(
1435                                            product_name,
1436                                            undefined),
1437                            case NameFromApp of
1438                                undefined ->
1439                                    Info0;
1440                                _ ->
1441                                    Info0#{product_name => NameFromApp,
1442                                           product_overridden => true}
1443                            end;
1444                        _ ->
1445                            Info0#{product_name => NameFromEnv,
1446                                   product_overridden => true}
1447                    end,
1448
1449            Info2 = case VersionFromEnv of
1450                        undefined ->
1451                            VersionFromApp = string_from_app_env(
1452                                               product_version,
1453                                               undefined),
1454                            case VersionFromApp of
1455                                undefined ->
1456                                    Info1;
1457                                _ ->
1458                                    Info1#{product_version => VersionFromApp,
1459                                           product_overridden => true}
1460                            end;
1461                        _ ->
1462                            Info1#{product_version => VersionFromEnv,
1463                                   product_overridden => true}
1464                    end,
1465            persistent_term:put(PTKey, Info2),
1466            Info2
1467    end.
1468
1469string_from_app_env(Key, Default) ->
1470    case application:get_env(rabbit, Key) of
1471        {ok, Val} ->
1472            case io_lib:deep_char_list(Val) of
1473                true ->
1474                    case lists:flatten(Val) of
1475                        ""     -> Default;
1476                        String -> String
1477                    end;
1478                false ->
1479                    Default
1480            end;
1481        undefined ->
1482            Default
1483    end.
1484
1485base_product_name() ->
1486    %% This function assumes the `rabbit` application was loaded in
1487    %% product_info().
1488    {ok, Product} = application:get_key(rabbit, description),
1489    Product.
1490
1491base_product_version() ->
1492    %% This function assumes the `rabbit` application was loaded in
1493    %% product_info().
1494    rabbit_misc:version().
1495
1496motd_file() ->
1497    %% Precendence is:
1498    %%   1. The environment variable;
1499    %%   2. The `motd_file` configuration parameter;
1500    %%   3. The default value.
1501    Context = rabbit_prelaunch:get_context(),
1502    case Context of
1503        #{motd_file := File,
1504          var_origins := #{motd_file := environment}}
1505          when File =/= undefined ->
1506            File;
1507        _ ->
1508            Default = case Context of
1509                          #{motd_file := File} -> File;
1510                          _                    -> undefined
1511                      end,
1512            string_from_app_env(motd_file, Default)
1513    end.
1514
1515motd() ->
1516    case motd_file() of
1517        undefined ->
1518            undefined;
1519        File ->
1520            case file:read_file(File) of
1521                {ok, MOTD} -> string:trim(MOTD, trailing, [$\r,$\n]);
1522                {error, _} -> undefined
1523            end
1524    end.
1525
1526home_dir() ->
1527    case init:get_argument(home) of
1528        {ok, [[Home]]} -> filename:absname(Home);
1529        Other          -> Other
1530    end.
1531
1532config_files() ->
1533    rabbit_config:config_files().
1534
1535%% We don't want this in fhc since it references rabbit stuff. And we can't put
1536%% this in the bootstep directly.
1537start_fhc() ->
1538    ok = rabbit_sup:start_restartable_child(
1539      file_handle_cache,
1540      [fun rabbit_alarm:set_alarm/1, fun rabbit_alarm:clear_alarm/1]),
1541    ensure_working_fhc().
1542
1543ensure_working_fhc() ->
1544    %% To test the file handle cache, we simply read a file we know it
1545    %% exists (Erlang kernel's .app file).
1546    %%
1547    %% To avoid any pollution of the application process' dictionary by
1548    %% file_handle_cache, we spawn a separate process.
1549    Parent = self(),
1550    TestFun = fun() ->
1551        ReadBuf = case application:get_env(rabbit, fhc_read_buffering) of
1552            {ok, true}  -> "ON";
1553            {ok, false} -> "OFF"
1554        end,
1555        WriteBuf = case application:get_env(rabbit, fhc_write_buffering) of
1556            {ok, true}  -> "ON";
1557            {ok, false} -> "OFF"
1558        end,
1559        ?LOG_INFO("FHC read buffering: ~s", [ReadBuf],
1560                  #{domain => ?RMQLOG_DOMAIN_GLOBAL}),
1561        ?LOG_INFO("FHC write buffering: ~s", [WriteBuf],
1562                  #{domain => ?RMQLOG_DOMAIN_GLOBAL}),
1563        Filename = filename:join(code:lib_dir(kernel, ebin), "kernel.app"),
1564        {ok, Fd} = file_handle_cache:open(Filename, [raw, binary, read], []),
1565        {ok, _} = file_handle_cache:read(Fd, 1),
1566        ok = file_handle_cache:close(Fd),
1567        Parent ! fhc_ok
1568    end,
1569    TestPid = spawn_link(TestFun),
1570    %% Because we are waiting for the test fun, abuse the
1571    %% 'mnesia_table_loading_retry_timeout' parameter to find a sane timeout
1572    %% value.
1573    Timeout = rabbit_table:retry_timeout(),
1574    receive
1575        fhc_ok                       -> ok;
1576        {'EXIT', TestPid, Exception} -> throw({ensure_working_fhc, Exception})
1577    after Timeout ->
1578            throw({ensure_working_fhc, {timeout, TestPid}})
1579    end.
1580