Packages
High-performance Telegram MTProto proxy server
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
src/mtp_metric.erl
%%% @author sergey <me@seriyps.ru>
%%% @copyright (C) 2018, sergey
%%% @doc
%%% Backend-agnostic interface for logging metrics.
%%% Made with prometheus.erl in mind, but might be used with smth else
%%% @end
%%% Created : 15 May 2018 by sergey <me@seriyps.ru>
-module(mtp_metric).
-export([count_inc/3,
gauge_set/3,
histogram_observe/3,
rt/2, rt/3]).
-export([passive_metrics/0,
active_metrics/0]).
-define(APP, mtproto_proxy).
-define(PD_KEY, {?MODULE, context_labels}).
-type metric_type() :: gauge | count | histogram.
-type metric_name() :: [atom()].
-type metric_doc() :: string().
count_inc(Name, Value, Extra) ->
notify(count, Name, Value, Extra).
gauge_set(Name, Value, Extra) ->
notify(gauge, Name, Value, Extra).
histogram_observe(Name, Value, Extra) ->
notify(histogram, Name, Value, Extra).
rt(Name, Fun) ->
rt(Name, Fun, #{}).
rt(Name, Fun, Extra) ->
Start = erlang:monotonic_time(),
try
Fun()
after
notify(histogram, Name, erlang:monotonic_time() - Start, Extra)
end.
notify(Type, Name, Value, Extra) ->
case get_backend() of
undefined ->
false;
Mod ->
Mod:notify(Type, Name, Value, Extra)
end.
get_backend() ->
%% Cache resutl of application:get_env in process dict because it's on the hot path
case erlang:get(metric_backend) of
undefined ->
case application:get_env(?APP, metric_backend) of
{ok, Mod} when Mod =/= false;
Mod =/= undefined ->
erlang:put(metric_backend, Mod),
Mod;
_ ->
erlang:put(metric_backend, false),
undefined
end;
false ->
undefined;
Mod ->
Mod
end.
-spec passive_metrics() -> [{metric_type(), metric_name(), metric_doc(),
[{Labels, Value}]}]
when
Labels :: #{atom() => binary() | atom()},
Value :: integer() | float().
passive_metrics() ->
DownStatus = mtp_config:status(),
[{gauge, [?APP, dc_num_downstreams],
"Count of connections to downstream",
[{#{dc => DcId}, NDowns}
|| #{n_downstreams := NDowns, dc_id := DcId} <- DownStatus]},
{gauge, [?APP, dc_num_upstreams],
"Count of upstreams connected to DC",
[{#{dc => DcId}, NUps}
|| #{n_upstreams := NUps, dc_id := DcId} <- DownStatus]},
{gauge, [?APP, dc_upstreams_per_downstream],
"Count of upstreams connected to DC",
lists:flatmap(
fun(#{min := Min,
max := Max,
dc_id := DcId}) ->
[{#{dc => DcId, meter => min}, Min},
{#{dc => DcId, meter => max}, Max}]
end, DownStatus)}
|
[{gauge, [?APP, connections, count],
"Count of ranch connections",
[{#{listener => H}, proplists:get_value(all_connections, P)}
|| {H, P} <- mtproto_proxy_app:mtp_listeners()]}] ].
-spec active_metrics() -> [{metric_type(), metric_name(), metric_doc(), Opts}]
when
Opts :: #{duration_units => atom(),
buckets => [number()],
labels => [atom()]}.
active_metrics() ->
[{count, [?APP, in_connection, total],
"MTP incoming connection",
#{labels => [listener]}},
{count, [?APP, in_connection_closed, total],
"MTP incoming connection closed",
#{labels => [listener]}},
{histogram, [?APP, session_lifetime, seconds],
"Time from in connection open to session process termination",
#{duration_unit => seconds,
buckets => [0.2, 0.5, 1, 5, 10, 30, 60, 150, 300, 600, 1200],
labels => [listener]
}},
{count, [?APP, inactive_timeout, total],
"Connection closed by timeout because of no activity",
#{labels => [listener]}},
{count, [?APP, inactive_hibernate, total],
"Connection goes to hibernate by timeout because of no activity",
#{labels => [listener]}},
{count, [?APP, timer_switch, total],
"Connection timeout mode switches",
#{labels => [listener, from, to]}},
{count, [?APP, healthcheck, total],
"Upstream self-healthcheck triggered some action",
#{labels => [action]}},
{count, [?APP, received, downstream, bytes],
"Bytes transmitted from downstream socket",
#{labels => [dc_id]}},
{count, [?APP, received, upstream, bytes],
"Bytes transmitted from upstream socket",
#{labels => [listener]}},
{count, [?APP, sent, downstream, bytes],
"Bytes sent to downstream socket",
#{labels => [dc_id]}},
{count, [?APP, sent, upstream, bytes],
"Bytes sent to upstream socket",
#{labels => [listener]}},
{histogram, [?APP, tracker_packet_size, bytes],
"Received packet size",
#{labels => [direction],
buckets => {exponential, 8, 4, 8}}},
{histogram, [?APP, tg_packet_size, bytes],
"Proxied telegram protocol packet size",
#{labels => [direction],
buckets => {exponential, 8, 4, 8}}},
{count, [?APP, protocol_error, total],
"Proxy protocol errors",
#{labels => [reason]}},
{count, [?APP, protocol_ok, total],
"Proxy upstream protocol type",
#{labels => [listener, protocol]}},
{count, [?APP, out_connect_ok, total],
"Proxy out connections",
#{labels => [dc_id]}},
{count, [?APP, out_connect_error, total],
"Proxy out connect errors",
#{labels => [dc_id, reason]}},
{count, [?APP, down_backpressure, total],
"Times downstream backpressure state was changed",
#{labels => [dc_id, state]}},
{histogram, [?APP, upstream_send_duration, seconds],
"Duration of tcp send calls to upstream",
#{duration_unit => seconds,
%% buckets => ?MS_BUCKETS
labels => [listener]
}},
{histogram, [?APP, downstream_send_duration, seconds],
"Duration of tcp send calls to downstream",
#{duration_unit => seconds,
%% buckets => ?MS_BUCKETS
labels => [dc]
}},
{count, [?APP, upstream_send_error, total],
"Count of tcp send errors to upstream",
#{labels => [listener, reason]}}
].