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