Current section

Files

Jump to
prometheus_process_collector src prometheus_process_collector.erl
Raw

src/prometheus_process_collector.erl

-module(prometheus_process_collector).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC("Prometheus OS process collector API").
-on_load(init/0).
-nifs([get_process_info/0]).
-export([deregister_cleanup/1, collect_mf/2, collect_metrics/2]).
-export([get_process_info/0]).
-behaviour(prometheus_collector).
-define(APPNAME, prometheus_process_collector).
-define(LIBNAME, prometheus_process_collector).
-define(METRICS, [
{process_open_fds, gauge, "Number of open file descriptors."},
{process_max_fds, gauge, "Maximum number of open file descriptors."},
{process_start_time_seconds, gauge, "Start time of the process since unix epoch in seconds."},
{process_uptime_seconds, counter, "Process uptime in seconds."},
{process_threads_total, gauge, "Process Threads count."},
{process_virtual_memory_bytes, gauge, "Virtual memory size in bytes."},
{process_resident_memory_bytes, gauge, "Resident memory size in bytes."},
{process_cpu_seconds_total, counter, "Process CPU seconds total.", fun(Info) ->
prometheus_model_helpers:counter_metrics([
{[{kind, utime}], proplists:get_value(process_utime_seconds, Info)},
{[{kind, stime}], proplists:get_value(process_stime_seconds, Info)}
])
end},
{process_max_resident_memory_bytes, gauge, "Maximum resident set size used."},
{process_noio_pagefaults_total, counter,
"Number of page faules serviced without any I/O activity."},
{process_io_pagefaults_total, counter,
"Number of page faults serviced that required I/O activity."},
{process_swaps_total, counter, "Number of times a process was \"swapped\" out of main memory."},
{process_disk_reads_total, counter, "Number of times the file system had to perform input."},
{process_disk_writes_total, counter, "Number of times the file system had to perform output."},
{process_signals_delivered_total, counter, "Number of signals delivered."},
{process_voluntary_context_switches_total, counter,
"Number of times a context switch resulted due to a "
"process voluntarily giving up the processor."},
{process_involuntary_context_switches_total, counter,
"Number of times a context switch resulted due to a "
"higher priority process becoming runnable or because the "
"current process exceeded its time slice."}
]).
%%====================================================================
%% Collector API
%%====================================================================
?DOC("Deregister collector. No cleanup logic needed.").
-spec deregister_cleanup(Registry) -> ok when
Registry :: prometheus_registry:registry().
deregister_cleanup(_) ->
ok.
?DOC("Calls `Callback` for each `MetricFamily` of this collector").
-spec collect_mf(Registry, Callback) -> ok when
Registry :: prometheus_registry:registry(),
Callback :: prometheus_collector:collect_mf_callback().
collect_mf(_Registry, Callback) ->
ProcessInfo = get_process_info(),
[mf(Callback, Metric, ProcessInfo) || Metric <- ?METRICS],
ok.
?DOC("Returns Metric list for each MetricFamily identified by `Name`.").
-spec collect_metrics(Name, Data) -> Metrics when
Name :: prometheus_metric:name(),
Data :: prometheus_collector:data(),
Metrics :: prometheus_model:'Metric'() | [prometheus_model:'Metric'()].
collect_metrics(_, {Fun, Proplist}) ->
Fun(Proplist).
mf(Callback, Metric, Proplist) ->
{Name, Type, Help, Fun} =
case Metric of
{Key, Type1, Help1} ->
{Key, Type1, Help1, fun(Proplist1) ->
metric(Type1, [], proplists:get_value(Key, Proplist1))
end};
{Key, Type1, Help1, Fun1} ->
{Key, Type1, Help1, Fun1}
end,
Callback(prometheus_model_helpers:create_mf(Name, Help, Type, ?MODULE, {Fun, Proplist})).
%%====================================================================
%% Private Parts
%%====================================================================
metric(counter, Labels, Value) ->
prometheus_model_helpers:counter_metric(Labels, Value);
metric(gauge, Labels, Value) ->
prometheus_model_helpers:gauge_metric(Labels, Value).
?DOC("Get process info callback").
-spec get_process_info() -> proplists:proplist().
get_process_info() ->
erlang:nif_error("NIF library not loaded").
init() ->
SoName =
case code:priv_dir(?APPNAME) of
{error, bad_name} ->
case filelib:is_dir(filename:join(["..", priv])) of
true ->
filename:join(["..", priv, ?LIBNAME]);
_ ->
filename:join([priv, ?LIBNAME])
end;
Dir ->
filename:join(Dir, ?LIBNAME)
end,
erlang:load_nif(SoName, 0).