Packages
prometheus
2.2.0
6.1.3
6.1.2
6.1.1
6.1.0
6.0.3
6.0.2
6.0.1
6.0.0
5.1.1
5.1.0
5.0.0
4.13.0
retired
4.12.0
4.11.0
4.10.0
4.9.1
4.9.0
4.8.2
4.8.1
4.8.0
4.6.0
4.5.0
4.4.1
4.4.0
4.3.0
4.2.2
4.2.0
4.1.0
4.0.1
4.0.0
3.5.1
3.5.0
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.2
3.3.1
3.3.0
3.2.3
3.2.2
3.2.1
3.1.1
3.1.0
3.0.1
3.0.0
3.0.0-rc1
3.0.0-alpha9
3.0.0-alpha8
3.0.0-alpha7
3.0.0-alpha6
3.0.0-alpha5
3.0.0-alpha4
3.0.0-alpha3
3.0.0-alpha2
3.0.0-alpha10
3.0.0-alpha1
2.2.0
2.1.0
2.0.0
1.7.0
1.6.0
1.5.0
1.0.2
1.0.1
1.0.0
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Prometheus.io client in Erlang
Current section
Files
Jump to
Current section
Files
src/formats/prometheus_text_format.erl
-module(prometheus_text_format).
-export([content_type/0,
format/0,
format/1]).
-ifdef(TEST).
-export([escape_metric_help/1,
escape_label_value/1]).
-endif.
-include("prometheus.hrl").
-include("prometheus_model.hrl").
-behaviour(prometheus_format).
%%====================================================================
%% Format API
%%====================================================================
-spec content_type() -> binary().
content_type() ->
<<"text/plain; version=0.0.4">>.
%% @equiv format(default)
-spec format() -> binary().
format() ->
format(default).
-spec format(Registry :: prometheus_registry:registry()) -> binary().
format(Registry) ->
{ok, Fd} = ram_file:open("", [write, read, binary]),
Callback = fun (_, Collector) ->
registry_collect_callback(Fd, Registry, Collector)
end,
prometheus_registry:collect(Registry, Callback),
file:write(Fd, io_lib:format("\n", [])),
{ok, Size} = ram_file:get_size(Fd),
{ok, Str} = file:pread(Fd, 0, Size),
ok = file:close(Fd),
Str.
%%====================================================================
%% Private Parts
%%====================================================================
registry_collect_callback(Fd, Registry, Collector) ->
Callback = fun (MF) ->
emit_mf_prologue(Fd, MF),
emit_mf_metrics(Fd, MF)
end,
prometheus_collector:collect_mf(Collector, Callback, Registry).
emit_mf_prologue(Fd, #'MetricFamily'{name=Name, help=Help, type=Type}) ->
Bytes = io_lib:format("# TYPE ~s ~s\n# HELP ~s ~s\n",
[Name, string_type(Type),
Name, escape_metric_help(Help)]),
file:write(Fd, Bytes).
emit_mf_metrics(Fd, #'MetricFamily'{name=Name, metric = Metrics}) ->
[emit_metric(Fd, Name, Metric) || Metric <- Metrics].
emit_metric(Fd, Name, #'Metric'{label=Labels,
counter=#'Counter'{value=Value}}) ->
emit_series(Fd, Name, Labels, Value);
emit_metric(Fd, Name, #'Metric'{label=Labels, gauge=#'Gauge'{value=Value}}) ->
emit_series(Fd, Name, Labels, Value);
emit_metric(Fd, Name, #'Metric'{label=Labels,
summary=#'Summary'{sample_count=Count,
sample_sum=Sum}}) ->
emit_series(Fd, [Name, "_count"], Labels, Count),
emit_series(Fd, [Name, "_sum"], Labels, Sum);
emit_metric(Fd, Name, #'Metric'{label=Labels,
histogram=#'Histogram'{sample_count=Count,
sample_sum=Sum,
bucket=Buckets}}) ->
[emit_histogram_bucket(Fd, Name, Labels, Bucket) || Bucket <- Buckets],
emit_series(Fd, [Name, "_count"], Labels, Count),
emit_series(Fd, [Name, "_sum"], Labels, Sum).
emit_histogram_bucket(Fd, Name, Labels, #'Bucket'{cumulative_count=BCount,
upper_bound=BBound}) ->
BLValue = bound_to_label_value(BBound),
emit_series(Fd, [Name, "_bucket"],
Labels ++ [#'LabelPair'{name="le", value=BLValue}], BCount).
string_type('COUNTER') ->
"counter";
string_type('GAUGE') ->
"gauge";
string_type('SUMMARY') ->
"summary";
string_type('HISTOGRAM') ->
"histogram";
string_type('UNTYPED') ->
"untyped".
labels_string([]) -> "";
labels_string(Labels) ->
Fun = fun (#'LabelPair'{name=Name, value=Value}) ->
io_lib:format("~s=\"~s\"", [Name, escape_label_value(Value)])
end,
"{" ++ string:join(lists:map(Fun, Labels), ",") ++ "}".
emit_series(Fd, Name, Labels, undefined) ->
LString = labels_string(Labels),
file:write(Fd, io_lib:format("~s" ++ LString ++ " NaN\n", [Name]));
emit_series(Fd, Name, Labels, Value) ->
LString = labels_string(Labels),
file:write(Fd, io_lib:format("~s" ++ LString ++ " ~p\n", [Name, Value])).
escape_metric_help(Help) ->
sub(sub(Help, "\\", "\\\\\\\\"), "\n", "\\\\n").
bound_to_label_value(Bound) when is_number(Bound) ->
Bound;
bound_to_label_value(infinity) ->
"+Inf".
-spec escape_label_value(binary() | iolist() | undefined) -> string().
escape_label_value(LValue) when is_list(LValue)->
sub(sub(sub(LValue, "\\", "\\\\\\\\"), "\n", "\\\\n"), "\"", "\\\\\"");
escape_label_value(LValue) when is_binary(LValue) ->
escape_label_value(binary_to_list(LValue));
escape_label_value(LValue) ->
escape_label_value(io_lib:format("~p", [LValue])).
-spec sub(string() | atom(), string(), string()) -> string().
sub(Str, Old, New) when is_atom(Str) ->
sub(atom_to_list(Str), Old, New);
sub(Str, Old, New) ->
RegExp = "\\Q" ++ Old ++ "\\E",
re:replace(Str, RegExp, New, [global, {return, list}]).