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