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