1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2019-2021. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(megaco_test_global_sys_monitor). 22 23-export([start/0, stop/0, 24 reset_events/0, 25 events/0, 26 log/1]). 27-export([init/1]). 28 29-include("megaco_test_lib.hrl"). 30 31-define(NAME, ?MODULE). 32 33 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 36start() -> 37 Parent = self(), 38 proc_lib:start(?MODULE, init, [Parent]). 39 40stop() -> 41 cast(stop). 42 43%% This does not reset the global counter but the "collector" 44%% See events for more info. 45reset_events() -> 46 call(reset_events). 47 48events() -> 49 events(infinity). 50 51events(Timeout) when (Timeout =:= infinity) orelse 52 (is_integer(Timeout) andalso (Timeout > 0)) -> 53 call(events, Timeout). 54 55log(Event) -> 56 cast({node(), Event}). 57 58 59%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 60 61init(Parent) -> 62 process_flag(priority, high), 63 case global:register_name(?NAME, self()) of 64 yes -> 65 info_msg("Starting as ~p (on ~p)", [self(), node()]), 66 proc_lib:init_ack(Parent, {ok, self()}), 67 loop(#{parent => Parent, ev_cnt => 0, evs => []}); 68 no -> 69 warning_msg("Already started", []), 70 proc_lib:init_ack(Parent, {error, already_started}), 71 exit(normal) 72 end. 73 74 75%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 76 77loop(State) -> 78 receive 79 {?MODULE, stop} -> 80 warning_msg("Stopping with ~w events counted", 81 [maps:get(ev_cnt, State)]), 82 exit(normal); 83 84 {?MODULE, Ref, From, reset_events} -> 85 TotEvCnt = maps:get(ev_cnt, State), 86 EvCnt = length(maps:get(evs, State)), 87 info_msg("Reset events when" 88 "~n Total Number of Events: ~p" 89 "~n Current Number of Events: ~p", 90 [TotEvCnt, EvCnt]), 91 From ! {?MODULE, Ref, {ok, {TotEvCnt, EvCnt}}}, 92 loop(State#{evs => []}); 93 94 {?MODULE, Ref, From, events} -> 95 Evs = maps:get(evs, State), 96 From ! {?MODULE, Ref, lists:reverse(Evs)}, 97 loop(State); 98 99 {?MODULE, {Node, Event}} -> 100 State2 = process_event(State, Node, Event), 101 loop(State2); 102 103 {nodedown = Event, Node} -> 104 State2 = process_event(State, Node, Event), 105 loop(State2); 106 107 _ -> 108 loop(State) 109 end. 110 111 112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 113 114process_event(State, Node, {Pid, TS, Tag, Info}) -> 115 process_system_event(State, Node, Pid, TS, Tag, Info); 116 117process_event(State, Node, {TS, starting}) -> 118 FTS = megaco:format_timestamp(TS), 119 info_msg("System Monitor starting on node ~p at ~s", [Node, FTS]), 120 if 121 (Node =/= node()) -> 122 erlang:monitor_node(Node, true); 123 true -> 124 ok 125 end, 126 State; 127 128process_event(State, Node, {TS, stopping}) -> 129 FTS = ?FTS(TS), 130 info_msg("System Monitor stopping on node ~p at ~s", [Node, FTS]), 131 if 132 (Node =/= node()) -> 133 erlang:monitor_node(Node, false); 134 true -> 135 ok 136 end, 137 State; 138 139process_event(State, Node, {TS, already_started}) -> 140 FTS = megaco:format_timestamp(TS), 141 info_msg("System Monitor already started on node ~p at ~s", [Node, FTS]), 142 State; 143 144process_event(State, Node, nodedown) -> 145 info_msg("Node ~p down", [Node]), 146 State; 147 148process_event(State, Node, Event) -> 149 warning_msg("Received unknown event from node ~p:" 150 "~n ~p", [Node, Event]), 151 State. 152 153 154%% System Monitor events 155%% We only *count* system events 156process_system_event(#{ev_cnt := Cnt, evs := Evs} = State, 157 Node, Pid, TS, long_gc = Ev, Info) -> 158 print_system_event(f("Long GC (~w)", [length(Evs)]), Node, Pid, TS, Info), 159 State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]}; 160process_system_event(#{ev_cnt := Cnt, evs := Evs} = State, 161 Node, Pid, TS, long_schedule = Ev, Info) -> 162 print_system_event(f("Long Schedule (~w)", [length(Evs)]), Node, Pid, TS, Info), 163 State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]}; 164process_system_event(#{ev_cnt := Cnt, evs := Evs} = State, 165 Node, Pid, TS, large_heap = Ev, Info) -> 166 print_system_event(f("Large Heap (~w)", [length(Evs)]), Node, Pid, TS, Info), 167 State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]}; 168process_system_event(#{ev_cnt := Cnt, evs := Evs} = State, 169 Node, Pid, TS, busy_port = Ev, Info) -> 170 print_system_event(f("Busy port (~w)", [length(Evs)]), Node, Pid, TS, Info), 171 State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]}; 172process_system_event(#{ev_cnt := Cnt, evs := Evs} = State, 173 Node, Pid, TS, busy_dist_port = Ev, Info) -> 174 print_system_event(f("Busy dist port (~w)", [length(Evs)]), 175 Node, Pid, TS, Info), 176 State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]}; 177 178%% And everything else 179process_system_event(State, Node, Pid, TS, Tag, Info) -> 180 Pre = f("Unknown Event '~p'", [Tag]), 181 print_system_event(Pre, Node, Pid, TS, Info), 182 State. 183 184 185print_system_event(Pre, Node, Pid, TS, Info) -> 186 FTS = megaco:format_timestamp(TS), 187 warning_msg("~s from ~p (~p) at ~s:" 188 "~n ~p", [Pre, Node, Pid, FTS, Info]). 189 190f(F, A) -> 191 lists:flatten(io_lib:format(F, A)). 192 193 194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 195 196cast(Msg) -> 197 try global:send(?NAME, {?MODULE, Msg}) of 198 Pid when is_pid(Pid) -> 199 ok 200 catch 201 C:E:_ -> 202 {error, {catched, C, E}} 203 end. 204 205call(Req) -> 206 call(Req, infinity). 207 208call(Req, Timeout) -> 209 Ref = make_ref(), 210 try global:send(?NAME, {?MODULE, Ref, self(), Req}) of 211 Pid when is_pid(Pid) -> 212 receive 213 {?MODULE, Ref, Rep} -> 214 Rep 215 after Timeout -> 216 {error, timeout} 217 end 218 catch 219 C:E:_ -> 220 {error, {catched, C, E}} 221 end. 222 223 224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 225 226info_msg(F, A) -> 227 error_logger:info_msg(format_msg(F, A), []). 228 229warning_msg(F, A) -> 230 error_logger:warning_msg(format_msg(F, A), []). 231 232 233format_msg(F, A) -> 234 f("~n" ++ 235 "****** MEGACO TEST GLOBAL SYSTEM MONITOR ******~n~n" ++ 236 F ++ 237 "~n~n", 238 A). 239 240