1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2019-2019. 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(snmp_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("snmp_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 call(events). 50 51log(Event) -> 52 cast({node(), Event}). 53 54 55%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 56 57init(Parent) -> 58 process_flag(priority, high), 59 case global:register_name(?NAME, self()) of 60 yes -> 61 info_msg("Starting as ~p (on ~p)", [self(), node()]), 62 proc_lib:init_ack(Parent, {ok, self()}), 63 loop(#{parent => Parent, ev_cnt => 0, evs => []}); 64 no -> 65 warning_msg("Already started", []), 66 proc_lib:init_ack(Parent, {error, already_started}), 67 exit(normal) 68 end. 69 70 71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 72 73loop(State) -> 74 receive 75 {?MODULE, stop} -> 76 warning_msg("Stopping with ~w events counted", 77 [maps:get(ev_cnt, State)]), 78 exit(normal); 79 80 {?MODULE, Ref, From, reset_events} -> 81 TotEvCnt = maps:get(ev_cnt, State), 82 EvCnt = length(maps:get(evs, State)), 83 info_msg("Reset events when" 84 "~n Total Number of Events: ~p" 85 "~n Current Number of Events: ~p", 86 [TotEvCnt, EvCnt]), 87 From ! {?MODULE, Ref, {ok, {TotEvCnt, EvCnt}}}, 88 loop(State#{evs => []}); 89 90 {?MODULE, Ref, From, events} -> 91 Evs = maps:get(evs, State), 92 From ! {?MODULE, Ref, lists:reverse(Evs)}, 93 loop(State); 94 95 {?MODULE, {Node, Event}} -> 96 State2 = process_event(State, Node, Event), 97 loop(State2); 98 99 {nodedown = Event, Node} -> 100 State2 = process_event(State, Node, Event), 101 loop(State2); 102 103 _ -> 104 loop(State) 105 end. 106 107 108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 109 110process_event(State, Node, {Pid, TS, Tag, Info}) -> 111 process_system_event(State, Node, Pid, TS, Tag, Info); 112 113process_event(State, Node, {TS, starting}) -> 114 FTS = snmp_misc:format_timestamp(TS), 115 info_msg("System Monitor starting on node ~p at ~s", [Node, FTS]), 116 if 117 (Node =/= node()) -> 118 erlang:monitor_node(Node, true); 119 true -> 120 ok 121 end, 122 State; 123 124process_event(State, Node, {TS, stopping}) -> 125 FTS = ?FTS(TS), 126 info_msg("System Monitor stopping on node ~p at ~s", [Node, FTS]), 127 if 128 (Node =/= node()) -> 129 erlang:monitor_node(Node, false); 130 true -> 131 ok 132 end, 133 State; 134 135process_event(State, Node, {TS, already_started}) -> 136 FTS = snmp_misc:format_timestamp(TS), 137 info_msg("System Monitor already started on node ~p at ~s", [Node, FTS]), 138 State; 139 140process_event(State, Node, nodedown) -> 141 info_msg("Node ~p down", [Node]), 142 State; 143 144process_event(State, Node, Event) -> 145 warning_msg("Received unknown event from node ~p:" 146 "~n ~p", [Node, Event]), 147 State. 148 149 150%% System Monitor events 151%% We only *count* system events 152process_system_event(#{ev_cnt := Cnt, evs := Evs} = State, 153 Node, Pid, TS, long_gc = Ev, Info) -> 154 print_system_event(f("Long GC (~w)", [length(Evs)]), Node, Pid, TS, Info), 155 State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]}; 156process_system_event(#{ev_cnt := Cnt, evs := Evs} = State, 157 Node, Pid, TS, long_schedule = Ev, Info) -> 158 print_system_event(f("Long Schedule (~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, large_heap = Ev, Info) -> 162 print_system_event(f("Large Heap (~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, busy_port = Ev, Info) -> 166 print_system_event(f("Busy port (~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_dist_port = Ev, Info) -> 170 print_system_event(f("Busy dist port (~w)", [length(Evs)]), 171 Node, Pid, TS, Info), 172 State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]}; 173 174%% And everything else 175process_system_event(State, Node, Pid, TS, Tag, Info) -> 176 Pre = f("Unknown Event '~p'", [Tag]), 177 print_system_event(Pre, Node, Pid, TS, Info), 178 State. 179 180 181print_system_event(Pre, Node, Pid, TS, Info) -> 182 FTS = snmp_misc:format_timestamp(TS), 183 warning_msg("~s from ~p (~p) at ~s:" 184 "~n ~p", [Pre, Node, Pid, FTS, Info]). 185 186f(F, A) -> 187 lists:flatten(io_lib:format(F, A)). 188 189 190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 191 192cast(Msg) -> 193 try global:send(?NAME, {?MODULE, Msg}) of 194 Pid when is_pid(Pid) -> 195 ok 196 catch 197 C:E:_ -> 198 {error, {catched, C, E}} 199 end. 200 201call(Req) -> 202 call(Req, infinity). 203 204call(Req, Timeout) -> 205 Ref = make_ref(), 206 try global:send(?NAME, {?MODULE, Ref, self(), Req}) of 207 Pid when is_pid(Pid) -> 208 receive 209 {?MODULE, Ref, Rep} -> 210 Rep 211 after Timeout -> 212 {error, timeout} 213 end 214 catch 215 C:E:_ -> 216 {error, {catched, C, E}} 217 end. 218 219 220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 221 222info_msg(F, A) -> 223 error_logger:info_msg(format_msg(F, A), []). 224 225warning_msg(F, A) -> 226 error_logger:warning_msg(format_msg(F, A), []). 227 228 229format_msg(F, A) -> 230 f("~n" ++ 231 "****** SNMP TEST GLOBAL SYSTEM MONITOR ******~n~n" ++ 232 F ++ 233 "~n~n", 234 A). 235 236