Skip to content

Commit 78e298f

Browse files
committed
Add ability to customize product name, version & banner [WIP]
To override the product name (defaulting to "RabbitMQ"): * set the `$RABBITMQ_SERVER_PRODUCT_NAME` environment variable, or * set the `rabbit` application `product_name` variable. To override the product version: * set the `$RABBITMQ_SERVER_PRODUCT_VERSION` environment variable, or * set the `rabbit` application `product_version` variable. To add content to the banner (both the copy logged and the one printed to stdout), indicate the filename which contains it, à la `/etc/motd` using: * the `$RABBITMQ_SERVER_MOTD_FILE` environment variable, or * the `rabbit` application `motd` variable. Here is an example of the printed banner with name, version & motd configured: ## ## WeatherMQ 1.2.3 ## ## ########## Copyright (c) 2007-2020 Pivotal Software, Inc. ###### ## ########## Licensed under the MPL 1.1. Website: https://rabbitmq.com This is an example of a RabbitMQ message of the day. The message is written in Paris, France. \ / It is partly cloudy outside, with a _ /"".-. temperature of 12°C. Wind is around \_( ). 30-40 km/h, from south-west. /(___(__) Doc guides: https://rabbitmq.com/documentation.html Support: https://rabbitmq.com/contact.html Tutorials: https://rabbitmq.com/getstarted.html Monitoring: https://rabbitmq.com/monitoring.html Logs: /tmp/rabbitmq-test-instances/rabbit/log/[email protected] /tmp/rabbitmq-test-instances/rabbit/log/rabbit@cassini_upgrade.log Config file(s): /tmp/rabbitmq-test-instances/test.config Starting broker... completed with 0 plugins. New APIS are available to query those product informations and use them in e.g. plugins such as the management API/UI: * rabbit:product_info/0 * rabbit:product_name/0 * rabbit:product_version/0 * rabbit:product_motd/0
1 parent 3aa744f commit 78e298f

File tree

1 file changed

+156
-15
lines changed

1 file changed

+156
-15
lines changed

src/rabbit.erl

Lines changed: 156 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
-export([start/2, stop/1, prep_stop/1]).
3232
-export([start_apps/1, start_apps/2, stop_apps/1]).
33+
-export([product_infos/0, product_name/0, product_version/0, product_motd/0]).
3334
-export([log_locations/0, config_files/0]). %% for testing and mgmt-agent
3435
-export([is_booted/1, is_booted/0, is_booting/1, is_booting/0]).
3536

@@ -376,8 +377,9 @@ run_prelaunch_second_phase() ->
376377
start_it(StartType) ->
377378
case spawn_boot_marker() of
378379
{ok, Marker} ->
380+
Product = product_name(),
379381
T0 = erlang:timestamp(),
380-
rabbit_log:info("RabbitMQ is asked to start...", []),
382+
rabbit_log:info("~s is asked to start...", [Product]),
381383
try
382384
{ok, _} = application:ensure_all_started(rabbitmq_prelaunch,
383385
StartType),
@@ -387,8 +389,8 @@ start_it(StartType) ->
387389

388390
T1 = erlang:timestamp(),
389391
rabbit_log_prelaunch:debug(
390-
"Time to start RabbitMQ: ~p µs",
391-
[timer:now_diff(T1, T0)]),
392+
"Time to start ~s: ~p µs",
393+
[Product, timer:now_diff(T1, T0)]),
392394
stop_boot_marker(Marker),
393395
ok
394396
catch
@@ -436,10 +438,12 @@ stop() ->
436438
ok ->
437439
case rabbit_boot_state:get() of
438440
ready ->
439-
rabbit_log:info("RabbitMQ is asked to stop..."),
441+
Product = product_name(),
442+
rabbit_log:info("~s is asked to stop...", [Product]),
440443
do_stop(),
441444
rabbit_log:info(
442-
"Successfully stopped RabbitMQ and its dependencies"),
445+
"Successfully stopped ~s and its dependencies",
446+
[Product]),
443447
ok;
444448
stopped ->
445449
ok
@@ -463,7 +467,9 @@ stop_and_halt() ->
463467
try
464468
stop()
465469
catch Type:Reason ->
466-
rabbit_log:error("Error trying to stop RabbitMQ: ~p:~p", [Type, Reason]),
470+
rabbit_log:error(
471+
"Error trying to stop ~s: ~p:~p",
472+
[product_name(), Type, Reason]),
467473
error({Type, Reason})
468474
after
469475
%% Enclose all the logging in the try block.
@@ -519,9 +525,9 @@ stop_apps([]) ->
519525
ok;
520526
stop_apps(Apps) ->
521527
rabbit_log:info(
522-
lists:flatten(["Stopping RabbitMQ applications and their dependencies in the following order:~n",
528+
lists:flatten(["Stopping ~s applications and their dependencies in the following order:~n",
523529
[" ~p~n" || _ <- Apps]]),
524-
lists:reverse(Apps)),
530+
[product_name() | lists:reverse(Apps)]),
525531
ok = app_utils:stop_applications(
526532
Apps, handle_app_error(error_during_shutdown)),
527533
case lists:member(rabbit, Apps) of
@@ -664,7 +670,7 @@ maybe_print_boot_progress(true, IterationsLeft) ->
664670
{memory, any()}].
665671

666672
status() ->
667-
{ok, Version} = application:get_key(rabbit, vsn),
673+
Version = product_version(),
668674
S1 = [{pid, list_to_integer(os:getpid())},
669675
%% The timeout value used is twice that of gen_server:call/2.
670676
{running_applications, rabbit_misc:which_applications()},
@@ -817,9 +823,10 @@ start(normal, []) ->
817823
try
818824
run_prelaunch_second_phase(),
819825

820-
rabbit_log:info("~n Starting RabbitMQ ~s on Erlang ~s~n ~s~n ~s~n",
821-
[rabbit_misc:version(), rabbit_misc:otp_release(),
826+
rabbit_log:info("~n Starting ~s ~s on Erlang ~s~n ~s~n ~s~n",
827+
[product_name(), product_version(), rabbit_misc:otp_release(),
822828
?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]),
829+
log_motd(),
823830
{ok, SupPid} = rabbit_sup:start_link(),
824831

825832
%% Compatibility with older RabbitMQ versions + required by
@@ -905,7 +912,7 @@ do_run_postlaunch_phase() ->
905912
end
906913
end, Plugins),
907914

908-
rabbit_log_prelaunch:debug("Marking RabbitMQ as running"),
915+
rabbit_log_prelaunch:debug("Marking ~s as running", [product_name()]),
909916
rabbit_boot_state:set(ready),
910917

911918
ok = rabbit_lager:broker_is_started(),
@@ -1059,8 +1066,8 @@ log_broker_started(Plugins) ->
10591066
"~n " ?BG32_START " " ?C_END " ~s").
10601067

10611068
print_banner() ->
1062-
{ok, Product} = application:get_key(description),
1063-
{ok, Version} = application:get_key(vsn),
1069+
Product = product_name(),
1070+
Version = product_version(),
10641071
LineListFormatter = fun (Placeholder, [_ | Tail] = LL) ->
10651072
LF = lists:flatten([Placeholder || _ <- lists:seq(1, length(Tail))]),
10661073
{LF, LL};
@@ -1083,8 +1090,21 @@ print_banner() ->
10831090
%% padded list lines
10841091
{LogFmt, LogLocations} = LineListFormatter("~n ~ts", log_locations()),
10851092
{CfgFmt, CfgLocations} = LineListFormatter("~n ~ts", config_locations()),
1093+
{MOTDFormat, MOTDArgs} = case product_motd() of
1094+
undefined ->
1095+
{"", []};
1096+
MOTD ->
1097+
Lines = string:split(MOTD, "\n", all),
1098+
Padded = [case Line of
1099+
<<>> -> "\n";
1100+
_ -> [" ", Line, "\n"]
1101+
end
1102+
|| Line <- Lines],
1103+
{"~n~ts", [Padded]}
1104+
end,
10861105
io:format(Logo ++
1087-
"~n"
1106+
"~n" ++
1107+
MOTDFormat ++
10881108
"~n Doc guides: https://rabbitmq.com/documentation.html"
10891109
"~n Support: https://rabbitmq.com/contact.html"
10901110
"~n Tutorials: https://rabbitmq.com/getstarted.html"
@@ -1094,9 +1114,24 @@ print_banner() ->
10941114
"~n Config file(s): ~ts" ++ CfgFmt ++ "~n"
10951115
"~n Starting broker...",
10961116
[Product, Version, ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE] ++
1117+
MOTDArgs ++
10971118
LogLocations ++
10981119
CfgLocations).
10991120

1121+
log_motd() ->
1122+
case product_motd() of
1123+
undefined ->
1124+
ok;
1125+
MOTD ->
1126+
Lines = string:split(MOTD, "\n", all),
1127+
Padded = [case Line of
1128+
<<>> -> "\n";
1129+
_ -> [" ", Line, "\n"]
1130+
end
1131+
|| Line <- Lines],
1132+
rabbit_log:info("~n~ts", [string:trim(Padded, trailing, [$\r, $\n])])
1133+
end.
1134+
11001135
log_banner() ->
11011136
{FirstLog, OtherLogs} = case log_locations() of
11021137
[Head | Tail] ->
@@ -1236,6 +1271,112 @@ validate_msg_store_io_batch_size_and_credit_disc_bound(CreditDiscBound,
12361271
end
12371272
end.
12381273

1274+
-spec product_name() -> string().
1275+
1276+
product_name() ->
1277+
#{name := ProductName} = product_infos(),
1278+
ProductName.
1279+
1280+
-spec product_version() -> string().
1281+
1282+
product_version() ->
1283+
#{version := ProductVersion} = product_infos(),
1284+
ProductVersion.
1285+
1286+
-spec product_infos() -> #{name := string(),
1287+
version := string()}.
1288+
1289+
product_infos() ->
1290+
PTKey = {?MODULE, product},
1291+
try
1292+
%% The value is cached the first time to avoid calling the
1293+
%% application master many times just for that.
1294+
persistent_term:get(PTKey)
1295+
catch
1296+
error:badarg ->
1297+
%% FIXME: Move those variables to rabbit_env.
1298+
NameFromEnv = os:getenv("RABBITMQ_SERVER_PRODUCT_NAME"),
1299+
VersionFromEnv = os:getenv("RABBITMQ_SERVER_PRODUCT_VERSION"),
1300+
Info =
1301+
if
1302+
NameFromEnv =/= false andalso
1303+
VersionFromEnv =/= false ->
1304+
#{name => NameFromEnv,
1305+
version => VersionFromEnv};
1306+
true ->
1307+
_ = application:load(rabbit),
1308+
Name = case NameFromEnv of
1309+
false ->
1310+
string_from_app_env(
1311+
product_name,
1312+
base_product_name());
1313+
_ ->
1314+
NameFromEnv
1315+
end,
1316+
Version = case VersionFromEnv of
1317+
false ->
1318+
string_from_app_env(
1319+
product_version,
1320+
base_product_version());
1321+
_ ->
1322+
VersionFromEnv
1323+
end,
1324+
#{name => Name,
1325+
version => Version}
1326+
end,
1327+
persistent_term:put(PTKey, Info),
1328+
Info
1329+
end.
1330+
1331+
string_from_app_env(Key, Default) ->
1332+
case application:get_env(rabbit, Key) of
1333+
{ok, Val} ->
1334+
case io_lib:deep_char_list(Val) of
1335+
true ->
1336+
case lists:flatten(Val) of
1337+
"" -> Default;
1338+
String -> String
1339+
end;
1340+
false ->
1341+
Default
1342+
end;
1343+
undefined ->
1344+
Default
1345+
end.
1346+
1347+
base_product_name() ->
1348+
%% This function assumes the `rabbit` application was loaded in
1349+
%% product_infos().
1350+
{ok, Product} = application:get_key(rabbit, description),
1351+
Product.
1352+
1353+
base_product_version() ->
1354+
%% This function assumes the `rabbit` application was loaded in
1355+
%% product_infos().
1356+
rabbit_misc:version().
1357+
1358+
product_motd() ->
1359+
File = case os:getenv("RABBITMQ_SERVER_MOTD_FILE") of
1360+
false ->
1361+
_ = application:load(rabbit),
1362+
string_from_app_env(motd, default_motd_file());
1363+
Val ->
1364+
Val
1365+
end,
1366+
case File of
1367+
undefined ->
1368+
undefined;
1369+
_ ->
1370+
case file:read_file(File) of
1371+
{ok, MOTD} -> string:trim(MOTD, trailing, [$\r,$\n]);
1372+
{error, _} -> undefined
1373+
end
1374+
end.
1375+
1376+
default_motd_file() ->
1377+
#{config_base_dir := Dir} = rabbit_env:get_context(),
1378+
filename:join(Dir, "motd").
1379+
12391380
home_dir() ->
12401381
case init:get_argument(home) of
12411382
{ok, [[Home]]} -> Home;

0 commit comments

Comments
 (0)