2 % This module implements an lwes journaller.
4 % configuration is as follows
6 % [ { root, "." }, % journal root
7 % { name, "all_events.log" }, % journal name
8 % { interval, <rotation_interval> }, % interval for jouirnal file rotation
11 -module (lwes_journaller
).
13 -behaviour (gen_server
).
15 -include_lib ("lwes_internal.hrl").
18 -export ([ start_link
/1,
23 %% gen_server callbacks
41 %%====================================================================
43 %%====================================================================
44 start_link (Config
) ->
45 gen_server:start_link ( ?MODULE
, [Config
], []).
47 process_event (Event
, Pid
) ->
48 gen_server:cast (Pid
, {process, Event
}),
52 gen_server:cast (Pid
, {rotate
}).
54 %%====================================================================
55 %% gen_server callbacks
56 %%====================================================================
58 % get appication variables
59 Root
= proplists:get_value (root
, Config
, "."),
60 Name
= proplists:get_value (name
, Config
, "all_events.log"),
61 Interval
= proplists:get_value (interval
, Config
, 60),
64 % I want terminate to be called
65 process_flag (trap_exit
, true
),
68 { ok
, File
} = open (Root
, Name
, Ext
),
70 % setup rotation of journal
72 timer:apply_interval (Interval
* 1000, ?MODULE
, rotate
, [self()]),
76 journal_file_name
= Name
,
77 journal_file_ext
= Ext
,
78 journal_current
= File
,
79 journal_last_rotate
= seconds_since_epoch (),
84 handle_call (Request
, From
, State
) ->
85 error_logger:warning_msg ("Unrecognized call ~p from ~p~n",[Request
, From
]),
88 format_header (EventSize
, MillisTimestamp
, Ip
= {Ip1
,Ip2
,Ip3
,Ip4
}, Port
, SiteId
)
89 when ?
is_uint16(EventSize
), ?
is_uint64(MillisTimestamp
), ?
is_ip_addr (Ip
),
90 ?
is_uint16(Port
), ?
is_uint16(SiteId
) ->
91 <<EventSize:16/integer-unsigned
-big
, % 2 bytes
92 MillisTimestamp:64/integer-unsigned
-big
, % 8 bytes
93 Ip4:8/integer-unsigned
-big
, % 1 byte
94 Ip3:8/integer-unsigned
-big
, % 1 byte
95 Ip2:8/integer-unsigned
-big
, % 1 byte
96 Ip1:8/integer-unsigned
-big
, % 1 byte
97 Port:16/integer-unsigned
-big
, % 2 bytes
98 SiteId:16/integer-unsigned
-big
, % 2 bytes
99 0:32/integer-signed
-big
% 4 bytes
102 handle_cast ( {process, {udp
, _
, Ip
, Port
, B
}},
103 State
= #state
{ journal_current
= Journal
}) ->
105 M
= milliseconds_since_epoch (),
107 ok
= file:write ( Journal
,
108 [ format_header(S
, M
, Ip
, Port
, SiteId
),
112 handle_cast ( {rotate
}, State
= #state
{
114 journal_file_name
= Name
,
115 journal_file_ext
= Ext
,
116 journal_current
= File
,
117 journal_last_rotate
= LastRotate
120 rename (Root
, Name
, Ext
, LastRotate
),
121 {ok
, NewFile
} = open (Root
, Name
, Ext
),
122 { noreply
, State#state
{ journal_current
= NewFile
,
123 journal_last_rotate
= seconds_since_epoch () }};
124 handle_cast (Request
, State
) ->
125 error_logger:warning_msg ("Unrecognized cast ~p~n",[Request
]),
128 handle_info (Request
, State
) ->
129 error_logger:warning_msg ("Unrecognized info ~p~n",[Request
]),
132 terminate (_Reason
, #state
{
134 journal_file_name
= Name
,
135 journal_file_ext
= Ext
,
136 journal_current
= File
,
137 journal_last_rotate
= LastRotate
140 rename (Root
, Name
, Ext
, LastRotate
),
143 code_change (_OldVsn
, State
, _Extra
) ->
146 %%====================================================================
148 %%====================================================================
149 open (Root
, Name
, Ext
) ->
150 JournalFile
= filename:join ([Root
, string:join ([Name
, Ext
],".")]),
151 file:open (JournalFile
, [ write
, raw
, compressed
]).
153 rename (Root
, Name
, Ext
, LastRotate
) ->
154 {{Year
,Month
,Day
},{Hour
,Minute
,Second
}} =
155 calendar:now_to_universal_time(os:timestamp()),
160 ("~s.~4.10.0B~2.10.0B~2.10.0B~2.10.0B~2.10.0B~2.10.0B.~b.~b.~s",
161 [ Name
, Year
, Month
, Day
, Hour
, Minute
, Second
, LastRotate
,
162 seconds_since_epoch(), Ext
])]),
163 CurrentFile
= filename:join ([Root
, string:join ([Name
, Ext
],".")]),
164 error_logger:info_msg("rename ~p -> ~p",[CurrentFile
, NewFile
]),
165 ok
= file:rename (CurrentFile
, NewFile
).
167 milliseconds_since_epoch () ->
168 {Meg
, Sec
, Mic
} = os:timestamp(),
169 trunc (Meg
* 1000000000 + Sec
* 1000 + Mic
/ 1000).
171 seconds_since_epoch () ->
172 {M
, S
, _
} = os:timestamp(),
175 %%====================================================================
177 %%====================================================================
179 -include_lib ("eunit/include/eunit.hrl").