Skip to content

Commit 8d5cf5e

Browse files
committed
Add ability to customize product name, version & banner
To override the product name (defaulting to "RabbitMQ"): * set the `$RABBITMQ_PRODUCT_NAME` environment variable, or * set the `rabbit` application `product_name` variable. To override the product version: * set the `$RABBITMQ_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_MOTD_FILE` environment variable, or * the `rabbit` application `motd_file` variable. The default motd file is `/etc/rabbitmq/motd` on Unix and `%APPDATA%\RabbitMQ\motd.txt` on Windows. 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:motd_file/0 * rabbit:motd/0 [#170054940]
1 parent a5f8ac4 commit 8d5cf5e

File tree

3 files changed

+196
-12
lines changed

3 files changed

+196
-12
lines changed

docs/rabbitmq.conf.example

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,17 @@
520520
##
521521
# proxy_protocol = false
522522

523+
## Overriden product name and version.
524+
## They are set to "RabbitMQ" and the release version by default.
525+
# product.name = RabbitMQ
526+
# product.version = 1.2.3
527+
528+
## "Message of the day" file.
529+
## Its content is used to expand the logged and printed banners.
530+
## Default to /etc/rabbitmq/motd on Unix, %APPDATA%\RabbitMQ\motd.txt
531+
## on Windows.
532+
# motd_file = /etc/rabbitmq/motd
533+
523534
## ----------------------------------------------------------------------------
524535
## Advanced Erlang Networking/Clustering Options.
525536
##

priv/schema/rabbit.schema

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
% vim:ft=erlang:
12
% ==============================
23
% Rabbit app section
34
% ==============================
@@ -1110,6 +1111,23 @@ end}.
11101111
{validators, ["non_zero_positive_integer"]}
11111112
]}.
11121113

1114+
%% Product name & version overrides.
1115+
1116+
{mapping, "product.name", "rabbit.product_name", [
1117+
{datatype, string}
1118+
]}.
1119+
{mapping, "product.version", "rabbit.product_version", [
1120+
{datatype, string}
1121+
]}.
1122+
1123+
%% Message of the day file.
1124+
%% The content of that file is added to the banners, both logged and
1125+
%% printed.
1126+
1127+
{mapping, "motd_file", "rabbit.motd_file", [
1128+
{datatype, string}
1129+
]}.
1130+
11131131
% ==========================
11141132
% Lager section
11151133
% ==========================

src/rabbit.erl

Lines changed: 167 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030

3131
-export([start/2, stop/1, prep_stop/1]).
3232
-export([start_apps/1, start_apps/2, stop_apps/1]).
33+
-export([product_info/0,
34+
product_name/0,
35+
product_version/0,
36+
motd_file/0,
37+
motd/0]).
3338
-export([log_locations/0, config_files/0]). %% for testing and mgmt-agent
3439
-export([is_booted/1, is_booted/0, is_booting/1, is_booting/0]).
3540

@@ -435,10 +440,12 @@ stop() ->
435440
ok ->
436441
case rabbit_boot_state:get() of
437442
ready ->
438-
rabbit_log:info("RabbitMQ is asked to stop..."),
443+
Product = product_name(),
444+
rabbit_log:info("~s is asked to stop...", [Product]),
439445
do_stop(),
440446
rabbit_log:info(
441-
"Successfully stopped RabbitMQ and its dependencies"),
447+
"Successfully stopped ~s and its dependencies",
448+
[Product]),
442449
ok;
443450
stopped ->
444451
ok
@@ -462,7 +469,9 @@ stop_and_halt() ->
462469
try
463470
stop()
464471
catch Type:Reason ->
465-
rabbit_log:error("Error trying to stop RabbitMQ: ~p:~p", [Type, Reason]),
472+
rabbit_log:error(
473+
"Error trying to stop ~s: ~p:~p",
474+
[product_name(), Type, Reason]),
466475
error({Type, Reason})
467476
after
468477
%% Enclose all the logging in the try block.
@@ -518,9 +527,9 @@ stop_apps([]) ->
518527
ok;
519528
stop_apps(Apps) ->
520529
rabbit_log:info(
521-
lists:flatten(["Stopping RabbitMQ applications and their dependencies in the following order:~n",
530+
lists:flatten(["Stopping ~s applications and their dependencies in the following order:~n",
522531
[" ~p~n" || _ <- Apps]]),
523-
lists:reverse(Apps)),
532+
[product_name() | lists:reverse(Apps)]),
524533
ok = app_utils:stop_applications(
525534
Apps, handle_app_error(error_during_shutdown)),
526535
case lists:member(rabbit, Apps) of
@@ -663,7 +672,7 @@ maybe_print_boot_progress(true, IterationsLeft) ->
663672
{memory, any()}].
664673

665674
status() ->
666-
{ok, Version} = application:get_key(rabbit, vsn),
675+
Version = product_version(),
667676
S1 = [{pid, list_to_integer(os:getpid())},
668677
%% The timeout value used is twice that of gen_server:call/2.
669678
{running_applications, rabbit_misc:which_applications()},
@@ -816,9 +825,10 @@ start(normal, []) ->
816825
try
817826
run_prelaunch_second_phase(),
818827

819-
rabbit_log:info("~n Starting RabbitMQ ~s on Erlang ~s~n ~s~n ~s~n",
820-
[rabbit_misc:version(), rabbit_misc:otp_release(),
828+
rabbit_log:info("~n Starting ~s ~s on Erlang ~s~n ~s~n ~s~n",
829+
[product_name(), product_version(), rabbit_misc:otp_release(),
821830
?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]),
831+
log_motd(),
822832
{ok, SupPid} = rabbit_sup:start_link(),
823833

824834
%% Compatibility with older RabbitMQ versions + required by
@@ -904,7 +914,7 @@ do_run_postlaunch_phase() ->
904914
end
905915
end, Plugins),
906916

907-
rabbit_log_prelaunch:debug("Marking RabbitMQ as running"),
917+
rabbit_log_prelaunch:debug("Marking ~s as running", [product_name()]),
908918
rabbit_boot_state:set(ready),
909919

910920
ok = rabbit_lager:broker_is_started(),
@@ -1058,8 +1068,8 @@ log_broker_started(Plugins) ->
10581068
"~n " ?BG32_START " " ?C_END " ~s").
10591069

10601070
print_banner() ->
1061-
{ok, Product} = application:get_key(description),
1062-
{ok, Version} = application:get_key(vsn),
1071+
Product = product_name(),
1072+
Version = product_version(),
10631073
LineListFormatter = fun (Placeholder, [_ | Tail] = LL) ->
10641074
LF = lists:flatten([Placeholder || _ <- lists:seq(1, length(Tail))]),
10651075
{LF, LL};
@@ -1082,8 +1092,21 @@ print_banner() ->
10821092
%% padded list lines
10831093
{LogFmt, LogLocations} = LineListFormatter("~n ~ts", log_locations()),
10841094
{CfgFmt, CfgLocations} = LineListFormatter("~n ~ts", config_locations()),
1095+
{MOTDFormat, MOTDArgs} = case motd() of
1096+
undefined ->
1097+
{"", []};
1098+
MOTD ->
1099+
Lines = string:split(MOTD, "\n", all),
1100+
Padded = [case Line of
1101+
<<>> -> "\n";
1102+
_ -> [" ", Line, "\n"]
1103+
end
1104+
|| Line <- Lines],
1105+
{"~n~ts", [Padded]}
1106+
end,
10851107
io:format(Logo ++
1086-
"~n"
1108+
"~n" ++
1109+
MOTDFormat ++
10871110
"~n Doc guides: https://rabbitmq.com/documentation.html"
10881111
"~n Support: https://rabbitmq.com/contact.html"
10891112
"~n Tutorials: https://rabbitmq.com/getstarted.html"
@@ -1093,9 +1116,24 @@ print_banner() ->
10931116
"~n Config file(s): ~ts" ++ CfgFmt ++ "~n"
10941117
"~n Starting broker...",
10951118
[Product, Version, ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE] ++
1119+
MOTDArgs ++
10961120
LogLocations ++
10971121
CfgLocations).
10981122

1123+
log_motd() ->
1124+
case motd() of
1125+
undefined ->
1126+
ok;
1127+
MOTD ->
1128+
Lines = string:split(MOTD, "\n", all),
1129+
Padded = [case Line of
1130+
<<>> -> "\n";
1131+
_ -> [" ", Line, "\n"]
1132+
end
1133+
|| Line <- Lines],
1134+
rabbit_log:info("~n~ts", [string:trim(Padded, trailing, [$\r, $\n])])
1135+
end.
1136+
10991137
log_banner() ->
11001138
{FirstLog, OtherLogs} = case log_locations() of
11011139
[Head | Tail] ->
@@ -1235,6 +1273,123 @@ validate_msg_store_io_batch_size_and_credit_disc_bound(CreditDiscBound,
12351273
end
12361274
end.
12371275

1276+
-spec product_name() -> string().
1277+
1278+
product_name() ->
1279+
#{name := ProductName} = product_info(),
1280+
ProductName.
1281+
1282+
-spec product_version() -> string().
1283+
1284+
product_version() ->
1285+
#{version := ProductVersion} = product_info(),
1286+
ProductVersion.
1287+
1288+
-spec product_info() -> #{name := string(),
1289+
version := string()}.
1290+
1291+
product_info() ->
1292+
PTKey = {?MODULE, product},
1293+
try
1294+
%% The value is cached the first time to avoid calling the
1295+
%% application master many times just for that.
1296+
persistent_term:get(PTKey)
1297+
catch
1298+
error:badarg ->
1299+
{NameFromEnv, VersionFromEnv} =
1300+
case rabbit_env:get_context() of
1301+
#{product_name := NFE,
1302+
product_version := VFE} -> {NFE, VFE};
1303+
_ -> {undefined, undefined}
1304+
end,
1305+
1306+
Info =
1307+
if
1308+
NameFromEnv =/= undefined andalso
1309+
VersionFromEnv =/= undefined ->
1310+
#{name => NameFromEnv,
1311+
version => VersionFromEnv};
1312+
true ->
1313+
Name = case NameFromEnv of
1314+
undefined ->
1315+
string_from_app_env(
1316+
product_name,
1317+
base_product_name());
1318+
_ ->
1319+
NameFromEnv
1320+
end,
1321+
Version = case VersionFromEnv of
1322+
undefined ->
1323+
string_from_app_env(
1324+
product_version,
1325+
base_product_version());
1326+
_ ->
1327+
VersionFromEnv
1328+
end,
1329+
#{name => Name,
1330+
version => Version}
1331+
end,
1332+
persistent_term:put(PTKey, Info),
1333+
Info
1334+
end.
1335+
1336+
string_from_app_env(Key, Default) ->
1337+
case application:get_env(rabbit, Key) of
1338+
{ok, Val} ->
1339+
case io_lib:deep_char_list(Val) of
1340+
true ->
1341+
case lists:flatten(Val) of
1342+
"" -> Default;
1343+
String -> String
1344+
end;
1345+
false ->
1346+
Default
1347+
end;
1348+
undefined ->
1349+
Default
1350+
end.
1351+
1352+
base_product_name() ->
1353+
%% This function assumes the `rabbit` application was loaded in
1354+
%% product_info().
1355+
{ok, Product} = application:get_key(rabbit, description),
1356+
Product.
1357+
1358+
base_product_version() ->
1359+
%% This function assumes the `rabbit` application was loaded in
1360+
%% product_info().
1361+
rabbit_misc:version().
1362+
1363+
motd_file() ->
1364+
%% Precendence is:
1365+
%% 1. The environment variable;
1366+
%% 2. The `motd_file` configuration parameter;
1367+
%% 3. The default value.
1368+
Context = rabbit_env:get_context(),
1369+
case Context of
1370+
#{motd_file := File,
1371+
var_origins := #{motd_file := environment}}
1372+
when File =/= undefined ->
1373+
File;
1374+
_ ->
1375+
Default = case Context of
1376+
#{motd_file := File} -> File;
1377+
_ -> undefined
1378+
end,
1379+
string_from_app_env(motd_file, Default)
1380+
end.
1381+
1382+
motd() ->
1383+
case motd_file() of
1384+
undefined ->
1385+
undefined;
1386+
File ->
1387+
case file:read_file(File) of
1388+
{ok, MOTD} -> string:trim(MOTD, trailing, [$\r,$\n]);
1389+
{error, _} -> undefined
1390+
end
1391+
end.
1392+
12381393
home_dir() ->
12391394
case init:get_argument(home) of
12401395
{ok, [[Home]]} -> Home;

0 commit comments

Comments
 (0)