Improve indentation consistency of list interleave.
[beam_stats.git] / src / beam_stats_msg_graphite.erl
CommitLineData
a9ed8751
SK
1-module(beam_stats_msg_graphite).
2
3-include("include/beam_stats.hrl").
6e1a5b00 4-include("include/beam_stats_ets_table.hrl").
a9ed8751 5-include("include/beam_stats_msg_graphite.hrl").
4bb8ddfe
SK
6-include("include/beam_stats_process.hrl").
7-include("include/beam_stats_process_ancestry.hrl").
8-include("include/beam_stats_processes.hrl").
a9ed8751
SK
9
10-export_type(
11 [ t/0
12 ]).
13
14-export(
15 [ of_beam_stats/1
ece99ea3 16 , of_beam_stats/2
cdcb989e
PO
17 , to_iolist/1
18 , path_to_iolist/1
ece99ea3 19 , node_id_to_bin/1
a9ed8751
SK
20 ]).
21
22-define(T, #?MODULE).
23
24-type t() ::
25 ?T{}.
26
67948b18
SK
27%% ============================================================================
28%% API
29%% ============================================================================
30
a9ed8751
SK
31-spec of_beam_stats(beam_stats:t()) ->
32 [t()].
33of_beam_stats(#beam_stats{node_id=NodeID}=BeamStats) ->
34 NodeIDBin = node_id_to_bin(NodeID),
35 of_beam_stats(BeamStats, NodeIDBin).
36
37-spec of_beam_stats(beam_stats:t(), binary()) ->
38 [t()].
39of_beam_stats(#beam_stats
40 { timestamp = Timestamp
41 , node_id = _
42 , memory = Memory
a37cd038
SK
43 , io_bytes_in = IOBytesIn
44 , io_bytes_out = IOBytesOut
45 , context_switches = ContextSwitches
46 , reductions = Reductions
47 , run_queue = RunQueue
6e1a5b00 48 , ets = ETS
4bb8ddfe 49 , processes = Processes
a9ed8751
SK
50 },
51 <<NodeID/binary>>
52) ->
a37cd038
SK
53 Ts = Timestamp,
54 N = NodeID,
8fe744e7
SK
55 Msgs =
56 [ cons([N, <<"io">> , <<"bytes_in">> ], IOBytesIn , Ts)
57 , cons([N, <<"io">> , <<"bytes_out">>], IOBytesOut , Ts)
58 , cons([N, <<"context_switches">> ], ContextSwitches, Ts)
59 , cons([N, <<"reductions">> ], Reductions , Ts)
60 , cons([N, <<"run_queue">> ], RunQueue , Ts)
61 | of_memory(Memory, NodeID, Ts)
62 ]
63 ++ of_ets(ETS, NodeID, Ts)
64 ++ of_processes(Processes, NodeID, Ts),
65 lists:map(fun path_prefix_schema_version/1, Msgs).
a9ed8751 66
cdcb989e
PO
67-spec to_iolist(t()) ->
68 iolist().
69to_iolist(
67948b18
SK
70 ?T
71 { path = Path
72 , value = Value
73 , timestamp = Timestamp
74 }
75) ->
cdcb989e 76 PathIOList = path_to_iolist(Path),
67948b18
SK
77 ValueBin = integer_to_binary(Value),
78 TimestampInt = timestamp_to_integer(Timestamp),
79 TimestampBin = integer_to_binary(TimestampInt),
cdcb989e 80 [PathIOList, <<" ">>, ValueBin, <<" ">>, TimestampBin].
67948b18 81
cdcb989e
PO
82-spec path_to_iolist([binary()]) ->
83 iolist().
84path_to_iolist(Path) ->
85 interleave(Path, <<".">>).
9b9299d9 86
ece99ea3
SK
87-spec node_id_to_bin(node()) ->
88 binary().
89node_id_to_bin(NodeID) ->
90 NodeIDBin = atom_to_binary(NodeID, utf8),
91 re:replace(NodeIDBin, "[\@\.]", "_", [global, {return, binary}]).
92
67948b18
SK
93%% ============================================================================
94%% Helpers
95%% ============================================================================
96
8fe744e7
SK
97-spec path_prefix_schema_version(t()) ->
98 t().
99path_prefix_schema_version(?T{}=T) ->
100 path_prefix(T, schema_version()).
101
102-spec path_prefix(t(), binary()) ->
103 t().
104path_prefix(?T{path=Path}=T, <<Prefix/binary>>) ->
105 T?T{path = [Prefix | Path]}.
106
107-spec schema_version() ->
108 binary().
109schema_version() ->
110 <<"beam_stats_v0">>.
111
e1221e42
SK
112-spec interleave([A], A) ->
113 [A].
aef1a4a7
SK
114interleave([], _) ->
115 [];
116interleave([X], _) ->
117 [X];
cdcb989e
PO
118interleave([X|Xs], Sep) ->
119 [X, Sep | interleave(Xs, Sep)].
67948b18
SK
120
121-spec timestamp_to_integer(erlang:timestamp()) ->
122 non_neg_integer().
123timestamp_to_integer({Megaseconds, Seconds, _}) ->
124 Megaseconds * 1000000 + Seconds.
125
a9ed8751
SK
126-spec of_memory([{atom(), non_neg_integer()}], binary(), erlang:timestamp()) ->
127 [t()].
128of_memory(Memory, <<NodeID/binary>>, Timestamp) ->
129 ComponentToMessage =
130 fun ({Key, Value}) ->
131 KeyBin = atom_to_binary(Key, latin1),
d07a494b 132 cons([NodeID, <<"memory">>, KeyBin], Value, Timestamp)
a9ed8751
SK
133 end,
134 lists:map(ComponentToMessage, Memory).
135
7581255c 136-spec of_ets(beam_stats_ets:t(), binary(), erlang:timestamp()) ->
6e1a5b00
SK
137 [t()].
138of_ets(PerTableStats, <<NodeID/binary>>, Timestamp) ->
139 OfEtsTable = fun (Table) -> of_ets_table(Table, NodeID, Timestamp) end,
c37a5360
SK
140 MsgsNested = lists:map(OfEtsTable, PerTableStats),
141 MsgsFlattened = lists:append(MsgsNested),
142 aggregate_by_path(MsgsFlattened, Timestamp).
6e1a5b00
SK
143
144-spec of_ets_table(beam_stats_ets_table:t(), binary(), erlang:timestamp()) ->
145 [t()].
146of_ets_table(#beam_stats_ets_table
147 { id = ID
148 , name = Name
149 , size = Size
150 , memory = Memory
151 },
152 <<NodeID/binary>>,
153 Timestamp
154) ->
c37a5360
SK
155 IDType =
156 case ID =:= Name
157 of true -> <<"NAMED">>
158 ; false -> <<"TID">>
159 end,
6e1a5b00 160 NameBin = atom_to_binary(Name, latin1),
c37a5360 161 NameAndID = [NameBin, IDType],
6e1a5b00
SK
162 [ cons([NodeID, <<"ets_table">>, <<"size">> | NameAndID], Size , Timestamp)
163 , cons([NodeID, <<"ets_table">>, <<"memory">> | NameAndID], Memory, Timestamp)
164 ].
165
4bb8ddfe
SK
166-spec of_processes(beam_stats_processes:t(), binary(), erlang:timestamp()) ->
167 [t()].
168of_processes(
169 #beam_stats_processes
170 { individual_stats = Processes
171 , count_all = CountAll
172 , count_exiting = CountExiting
173 , count_garbage_collecting = CountGarbageCollecting
174 , count_registered = CountRegistered
175 , count_runnable = CountRunnable
176 , count_running = CountRunning
177 , count_suspended = CountSuspended
178 , count_waiting = CountWaiting
179 },
180 <<NodeID/binary>>,
181 Timestamp
182) ->
183 OfProcess = fun (P) -> of_process(P, NodeID, Timestamp) end,
184 PerProcessMsgsNested = lists:map(OfProcess, Processes),
185 PerProcessMsgsFlattened = lists:append(PerProcessMsgsNested),
697c496d 186 PerProcessMsgsAggregates = aggregate_by_path(PerProcessMsgsFlattened, Timestamp),
4bb8ddfe
SK
187 Ts = Timestamp,
188 N = NodeID,
189 [ cons([N, <<"processes_count_all">> ], CountAll , Ts)
190 , cons([N, <<"processes_count_exiting">> ], CountExiting , Ts)
191 , cons([N, <<"processes_count_garbage_collecting">>], CountGarbageCollecting, Ts)
192 , cons([N, <<"processes_count_registered">> ], CountRegistered , Ts)
193 , cons([N, <<"processes_count_runnable">> ], CountRunnable , Ts)
194 , cons([N, <<"processes_count_running">> ], CountRunning , Ts)
195 , cons([N, <<"processes_count_suspended">> ], CountSuspended , Ts)
196 , cons([N, <<"processes_count_waiting">> ], CountWaiting , Ts)
697c496d 197 | PerProcessMsgsAggregates
4bb8ddfe
SK
198 ].
199
200-spec of_process(beam_stats_process:t(), binary(), erlang:timestamp()) ->
201 [t()].
202of_process(
203 #beam_stats_process
f65a3845 204 { pid = _
4bb8ddfe
SK
205 , memory = Memory
206 , total_heap_size = TotalHeapSize
207 , stack_size = StackSize
208 , message_queue_len = MsgQueueLen
7dbc59b6 209 , reductions = Reductions
4bb8ddfe
SK
210 }=Process,
211 <<NodeID/binary>>,
212 Timestamp
213) ->
214 Origin = beam_stats_process:get_best_known_origin(Process),
215 OriginBin = proc_origin_to_bin(Origin),
4bb8ddfe
SK
216 Ts = Timestamp,
217 N = NodeID,
f65a3845
SK
218 [ cons([N, <<"process_memory">> , OriginBin], Memory , Ts)
219 , cons([N, <<"process_total_heap_size">> , OriginBin], TotalHeapSize , Ts)
220 , cons([N, <<"process_stack_size">> , OriginBin], StackSize , Ts)
221 , cons([N, <<"process_message_queue_len">> , OriginBin], MsgQueueLen , Ts)
7dbc59b6 222 , cons([N, <<"process_reductions">> , OriginBin], Reductions , Ts)
4bb8ddfe
SK
223 ].
224
697c496d
SK
225-spec aggregate_by_path([t()], erlang:timestamp()) ->
226 [t()].
227aggregate_by_path(Msgs, Timestamp) ->
228 Aggregate =
229 fun (?T{path=K, value=V}, ValsByPath) ->
230 dict:update_counter(K, V, ValsByPath)
231 end,
232 ValsByPathDict = lists:foldl(Aggregate, dict:new(), Msgs),
233 ValsByPathList = dict:to_list(ValsByPathDict),
234 [cons(Path, Value, Timestamp) || {Path, Value} <- ValsByPathList].
235
4bb8ddfe
SK
236-spec proc_origin_to_bin(beam_stats_process:best_known_origin()) ->
237 binary().
238proc_origin_to_bin({registered_name, Name}) ->
f65a3845
SK
239 NameBin = atom_to_binary(Name, utf8),
240 <<"named--", NameBin/binary>>;
4bb8ddfe
SK
241proc_origin_to_bin({ancestry, Ancestry}) ->
242 #beam_stats_process_ancestry
243 { raw_initial_call = InitCallRaw
244 , otp_initial_call = InitCallOTPOpt
245 , otp_ancestors = AncestorsOpt
246 } = Ancestry,
247 Blank = <<"NONE">>,
248 InitCallOTPBinOpt = hope_option:map(InitCallOTPOpt , fun mfa_to_bin/1),
249 InitCallOTPBin = hope_option:get(InitCallOTPBinOpt, Blank),
250 AncestorsBinOpt = hope_option:map(AncestorsOpt , fun ancestors_to_bin/1),
251 AncestorsBin = hope_option:get(AncestorsBinOpt , Blank),
252 InitCallRawBin = mfa_to_bin(InitCallRaw),
f65a3845
SK
253 << "spawned-via--"
254 , InitCallRawBin/binary
4bb8ddfe
SK
255 , "--"
256 , InitCallOTPBin/binary
257 , "--"
258 , AncestorsBin/binary
259 >>.
260
261ancestors_to_bin([]) ->
262 <<>>;
263ancestors_to_bin([A | Ancestors]) ->
264 ABin = ancestor_to_bin(A),
265 case ancestors_to_bin(Ancestors)
266 of <<>> ->
267 ABin
268 ; <<AncestorsBin/binary>> ->
269 <<ABin/binary, "-", AncestorsBin/binary>>
270 end.
271
272ancestor_to_bin(A) when is_atom(A) ->
273 atom_to_binary(A, utf8);
274ancestor_to_bin(A) when is_pid(A) ->
10bc7b71 275 <<"PID">>.
4bb8ddfe
SK
276
277-spec mfa_to_bin(mfa()) ->
278 binary().
279mfa_to_bin({Module, Function, Arity}) ->
280 ModuleBin = atom_to_binary(Module , utf8),
281 FunctionBin = atom_to_binary(Function, utf8),
282 ArityBin = erlang:integer_to_binary(Arity),
283 <<ModuleBin/binary, "-", FunctionBin/binary, "-", ArityBin/binary>>.
284
a37cd038
SK
285-spec cons([binary()], integer(), erlang:timestamp()) ->
286 t().
287cons(Path, Value, Timestamp) ->
288 ?T
289 { path = Path
290 , value = Value
291 , timestamp = Timestamp
292 }.
This page took 0.040557 seconds and 4 git commands to generate.