diff --git a/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl b/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl
index 102b95f4e..1b5b6ca9c 100644
--- a/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl
+++ b/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl
@@ -708,6 +708,8 @@ typename_to_spec("qos()", _Mod) ->
#{type => integer, minimum => 0, maximum => 2, example => 0};
typename_to_spec("{binary(), binary()}", _Mod) ->
#{type => object, example => #{}};
+typename_to_spec("{string(), string()}", _Mod) ->
+ #{type => object, example => #{}};
typename_to_spec("comma_separated_list()", _Mod) ->
#{type => string, example => <<"item1,item2">>};
typename_to_spec("comma_separated_binary()", _Mod) ->
diff --git a/apps/emqx_prometheus/i18n/emqx_prometheus_schema_i18n.conf b/apps/emqx_prometheus/i18n/emqx_prometheus_schema_i18n.conf
index 7f251ff4b..f25e35219 100644
--- a/apps/emqx_prometheus/i18n/emqx_prometheus_schema_i18n.conf
+++ b/apps/emqx_prometheus/i18n/emqx_prometheus_schema_i18n.conf
@@ -24,6 +24,35 @@ emqx_prometheus_schema {
zh: """数据推送间隔"""
}
}
+
+ headers {
+ desc {
+ en: """A list of HTTP Headers when pushing to Push Gateway.
+For example, { Authorization = "some-authz-tokens"}
"""
+ zh: """推送到 Push Gateway 的 HTTP Headers 列表。
+例如, { Authorization = "some-authz-tokens"}
"""
+ }
+ }
+
+ job_name {
+ desc {
+ en: """Job Name that is pushed to the Push Gateway. Available variables:
+- ${name}: Name of EMQX node.
+- ${host}: Host name of EMQX node.
+For example, when the EMQX node name is emqx@127.0.0.1
then the name
variable takes value emqx
and the host
variable takes value 127.0.0.1
.
+
+Default value is: ${name}/instance/${name}~${host}
+"""
+ zh: """推送到 Push Gateway 的 Job 名称。可用变量为:
+- ${name}: EMQX 节点的名称。
+- ${host}: EMQX 节点主机名。
+
+例如,当 EMQX 节点名为 emqx@127.0.0.1
则 name 变量的值为 emqx
,host 变量的值为 127.0.0.1
。
+
+默认值为: ${name}/instance/${name}~${host}
"""
+ }
+ }
+
enable {
desc {
en: """Turn Prometheus data pushing on or off"""
diff --git a/apps/emqx_prometheus/src/emqx_prometheus.app.src b/apps/emqx_prometheus/src/emqx_prometheus.app.src
index d95c89c3b..31f8cbfaf 100644
--- a/apps/emqx_prometheus/src/emqx_prometheus.app.src
+++ b/apps/emqx_prometheus/src/emqx_prometheus.app.src
@@ -2,7 +2,7 @@
{application, emqx_prometheus, [
{description, "Prometheus for EMQX"},
% strict semver, bump manually!
- {vsn, "5.0.3"},
+ {vsn, "5.0.4"},
{modules, []},
{registered, [emqx_prometheus_sup]},
{applications, [kernel, stdlib, prometheus, emqx]},
diff --git a/apps/emqx_prometheus/src/emqx_prometheus.erl b/apps/emqx_prometheus/src/emqx_prometheus.erl
index 5424c4e24..a66f275f8 100644
--- a/apps/emqx_prometheus/src/emqx_prometheus.erl
+++ b/apps/emqx_prometheus/src/emqx_prometheus.erl
@@ -98,8 +98,13 @@ handle_cast(_Msg, State) ->
{noreply, State}.
handle_info({timeout, Timer, ?TIMER_MSG}, State = #{timer := Timer}) ->
- #{interval := Interval, push_gateway_server := Server} = opts(),
- PushRes = push_to_push_gateway(Server),
+ #{
+ interval := Interval,
+ headers := Headers,
+ job_name := JobName,
+ push_gateway_server := Server
+ } = opts(),
+ PushRes = push_to_push_gateway(Server, Headers, JobName),
NewTimer = ensure_timer(Interval),
NewState = maps:update_with(PushRes, fun(C) -> C + 1 end, 1, State#{timer => NewTimer}),
%% Data is too big, hibernate for saving memory and stop system monitor warning.
@@ -107,18 +112,27 @@ handle_info({timeout, Timer, ?TIMER_MSG}, State = #{timer := Timer}) ->
handle_info(_Msg, State) ->
{noreply, State}.
-push_to_push_gateway(Uri) ->
+push_to_push_gateway(Uri, Headers, JobName) when is_list(Headers) ->
[Name, Ip] = string:tokens(atom_to_list(node()), "@"),
- Url = lists:concat([Uri, "/metrics/job/", Name, "/instance/", Name, "~", Ip]),
+ JobName1 = emqx_placeholder:preproc_tmpl(JobName),
+ JobName2 = binary_to_list(
+ emqx_placeholder:proc_tmpl(
+ JobName1,
+ #{<<"name">> => Name, <<"host">> => Ip}
+ )
+ ),
+
+ Url = lists:concat([Uri, "/metrics/job/", JobName2]),
Data = prometheus_text_format:format(),
- case httpc:request(post, {Url, [], "text/plain", Data}, ?HTTP_OPTIONS, []) of
- {ok, {{"HTTP/1.1", 200, "OK"}, _Headers, _Body}} ->
+ case httpc:request(post, {Url, Headers, "text/plain", Data}, ?HTTP_OPTIONS, []) of
+ {ok, {{"HTTP/1.1", 200, _}, _RespHeaders, _RespBody}} ->
ok;
Error ->
?SLOG(error, #{
msg => "post_to_push_gateway_failed",
error => Error,
- url => Url
+ url => Url,
+ headers => Headers
}),
failed
end.
diff --git a/apps/emqx_prometheus/src/emqx_prometheus_api.erl b/apps/emqx_prometheus/src/emqx_prometheus_api.erl
index 7466a1fd1..945c6eba9 100644
--- a/apps/emqx_prometheus/src/emqx_prometheus_api.erl
+++ b/apps/emqx_prometheus/src/emqx_prometheus_api.erl
@@ -121,6 +121,8 @@ prometheus_config_example() ->
enable => true,
interval => "15s",
push_gateway_server => <<"http://127.0.0.1:9091">>,
+ headers => #{'header-name' => 'header-value'},
+ job_name => <<"${name}/instance/${name}~${host}">>,
vm_dist_collector => enabled,
mnesia_collector => enabled,
vm_statistics_collector => enabled,
diff --git a/apps/emqx_prometheus/src/emqx_prometheus_schema.erl b/apps/emqx_prometheus/src/emqx_prometheus_schema.erl
index 688c9be58..c13d198a2 100644
--- a/apps/emqx_prometheus/src/emqx_prometheus_schema.erl
+++ b/apps/emqx_prometheus/src/emqx_prometheus_schema.erl
@@ -25,7 +25,8 @@
roots/0,
fields/1,
desc/1,
- translation/1
+ translation/1,
+ convert_headers/1
]).
namespace() -> "prometheus".
@@ -52,6 +53,26 @@ fields("prometheus") ->
desc => ?DESC(interval)
}
)},
+ {headers,
+ ?HOCON(
+ list({string(), string()}),
+ #{
+ default => #{},
+ required => false,
+ converter => fun ?MODULE:convert_headers/1,
+ desc => ?DESC(headers)
+ }
+ )},
+ {job_name,
+ ?HOCON(
+ binary(),
+ #{
+ default => <<"${name}/instance/${name}~${host}">>,
+ required => true,
+ desc => ?DESC(job_name)
+ }
+ )},
+
{enable,
?HOCON(
boolean(),
@@ -126,6 +147,17 @@ fields("prometheus") ->
desc("prometheus") -> ?DESC(prometheus);
desc(_) -> undefined.
+convert_headers(Headers) when is_map(Headers) ->
+ maps:fold(
+ fun(K, V, Acc) ->
+ [{binary_to_list(K), binary_to_list(V)} | Acc]
+ end,
+ [],
+ Headers
+ );
+convert_headers(Headers) when is_list(Headers) ->
+ Headers.
+
%% for CI test, CI don't load the whole emqx_conf_schema.
translation(Name) ->
emqx_conf_schema:translation(Name).
diff --git a/apps/emqx_prometheus/test/emqx_prometheus_SUITE.erl b/apps/emqx_prometheus/test/emqx_prometheus_SUITE.erl
index b9df1103b..77d9902a2 100644
--- a/apps/emqx_prometheus/test/emqx_prometheus_SUITE.erl
+++ b/apps/emqx_prometheus/test/emqx_prometheus_SUITE.erl
@@ -27,6 +27,8 @@
"prometheus {\n"
" push_gateway_server = \"http://127.0.0.1:9091\"\n"
" interval = \"1s\"\n"
+ " headers = { Authorization = \"some-authz-tokens\"}\n"
+ " job_name = \"${name}~${host}\"\n"
" enable = true\n"
" vm_dist_collector = enabled\n"
" mnesia_collector = enabled\n"
@@ -85,6 +87,25 @@ t_collector_no_crash_test(_) ->
prometheus_text_format:format(),
ok.
+t_assert_push(_) ->
+ meck:new(httpc, [passthrough]),
+ Self = self(),
+ AssertPush = fun(Method, Req = {Url, Headers, ContentType, _Data}, HttpOpts, Opts) ->
+ ?assertEqual(post, Method),
+ ?assertMatch("http://127.0.0.1:9091/metrics/job/test~127.0.0.1", Url),
+ ?assertEqual([{"Authorization", "some-authz-tokens"}], Headers),
+ ?assertEqual("text/plain", ContentType),
+ Self ! pass,
+ meck:passthrough([Method, Req, HttpOpts, Opts])
+ end,
+ meck:expect(httpc, request, AssertPush),
+ ?assertMatch(ok, emqx_prometheus_sup:start_child(emqx_prometheus)),
+ receive
+ pass -> ok
+ after 2000 ->
+ ct:fail(assert_push_request_failed)
+ end.
+
t_only_for_coverage(_) ->
?assertEqual("5.0.0", emqx_prometheus_proto_v1:introduced_in()),
ok.
diff --git a/changes/v5.0.15/feat-9722.en.md b/changes/v5.0.15/feat-9722.en.md
new file mode 100644
index 000000000..b86f37b83
--- /dev/null
+++ b/changes/v5.0.15/feat-9722.en.md
@@ -0,0 +1,3 @@
+Add the following configuration options for Pushing metrics to Prometheus Push Gateway:
+- `headers`: Allows custom HTTP request headers.
+- `job_name`: allows to customize the name of the Job pushed to Push Gateway.
diff --git a/changes/v5.0.15/feat-9722.zh.md b/changes/v5.0.15/feat-9722.zh.md
new file mode 100644
index 000000000..a806cb1de
--- /dev/null
+++ b/changes/v5.0.15/feat-9722.zh.md
@@ -0,0 +1,3 @@
+为 Prometheus 推送到 Push Gateway 新增以下配置项:
+- `headers`:允许自定义 HTTP 请求头。
+- `job_name`:允许自定义推送到 Push Gateway 的 Job 名称。