1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1998-2016. 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-module(nteventlog). 21-behaviour(gen_server). 22 23%% API 24-export([start_link/2, start/2, stop/0]). 25 26%% gen_server callbacks 27-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 28 terminate/2]). 29 30-record(state, {port, mfa}). 31 32%%---------------------------------------------------------------------- 33%% API 34%%---------------------------------------------------------------------- 35 36start_link(Ident, MFA) -> 37 gen_server:start_link({local, nteventlog}, nteventlog, 38 [Ident, MFA], []). 39 40start(Ident, MFA) -> 41 gen_server:start({local, nteventlog}, nteventlog, [Ident, MFA], []). 42 43stop() -> 44 gen_server:call(nteventlog, stop). 45 46%%---------------------------------------------------------------------- 47%% gen_server callbacks 48%%---------------------------------------------------------------------- 49 50init([Identifier,MFA0]) -> 51 process_flag(trap_exit, true), 52 process_flag(priority, low), 53 54 Port = case os:type() of 55 {win32, _OSname} -> start_portprogram(Identifier); 56 OS -> exit({unsupported_os, OS}) 57 end, 58 59 %% If we're using os_sup:error_report/2, 60 %% the setting of os_sup_errortag should be used as argument 61 MFA = case MFA0 of 62 {os_sup, error_report, [_Tag]} -> 63 Tag = os_mon:get_env(os_sup, os_sup_errortag), 64 {os_sup, error_report, [Tag]}; 65 _ -> 66 MFA0 67 end, 68 69 {ok, #state{port=Port, mfa=MFA}}. 70 71handle_call(stop, _From, State) -> 72 {stop, normal, stopped, State}. 73 74handle_cast(_Msg, State) -> 75 {noreply, State}. 76 77handle_info({_Port, {data, Data}}, #state{mfa={M,F,A}} = State) -> 78 T = parse_log(Data), 79 apply(M, F, [T | A]), 80 State#state.port ! {self(), {command, "A"}}, 81 {noreply, State}; 82handle_info({'EXIT', _Port, Reason}, State) -> 83 {stop, {port_died, Reason}, State#state{port=not_used}}; 84handle_info(_Info, State) -> 85 {noreply, State}. 86 87terminate(_Reason, State) -> 88 case State#state.port of 89 not_used -> ignore; 90 Port -> 91 port_close(Port) 92 end, 93 ok. 94 95%%---------------------------------------------------------------------- 96%% Internal functions 97%%---------------------------------------------------------------------- 98 99start_portprogram(Identifier) -> 100 Command = 101 "\"" ++ filename:join([code:priv_dir(os_mon),"bin","nteventlog.exe"]) ++ 102 "\" " ++ make_list(Identifier), 103 open_port({spawn,Command},[{packet,2}]). 104 105make_list(X) when is_atom(X) -> 106 atom_to_list(X); 107make_list(X) -> 108 X. 109 110holl_len([$H | Rest], Sum) -> 111 {Sum, Rest}; 112holl_len([ N | Rest], Sum) -> 113 NN = N - $0, 114 holl_len(Rest, Sum * 10 + NN). 115holl_len(L) -> 116 holl_len(L,0). 117 118splitlist(L,N) -> 119 {lists:sublist(L,N),lists:nthtail(N,L)}. 120 121hollerith(Str) -> 122 {Len, Rest} = holl_len(Str), 123 splitlist(Rest,Len). 124 125holl_time(Str) -> 126 {Holl,Rest} = hollerith(Str), 127 Rev = lists:reverse(Holl), 128 B = list_to_integer(lists:reverse(lists:sublist(Rev,6))), 129 A = list_to_integer(lists:reverse(lists:nthtail(6,Rev))), 130 {{A,B,0},Rest}. 131 132parse_log(Str) -> 133 {Time, Rest1} = holl_time(Str), 134 {Category,Rest2} = hollerith(Rest1), 135 {Facility,Rest3} = hollerith(Rest2), 136 {Severity,Rest4} = hollerith(Rest3), 137 {Message,_} = hollerith(Rest4), 138 {Time,Category,Facility,Severity,Message}. 139