Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first commit

  • Loading branch information...
commit 7cccb9a782f97325092d588a3c121d8e5d900cb8 0 parents
@vjache authored
1  Emakefile
@@ -0,0 +1 @@
+{'./src/*', [debug_info,load, {outdir, "./ebin/"}, {i, "./include/"}]}.
178 LICENSE
@@ -0,0 +1,178 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
14 Makefile
@@ -0,0 +1,14 @@
+REBAR=`which rebar || ./rebar`
+
+all: compile
+
+compile:
+ @$(REBAR) compile
+
+test: force
+ @$(REBAR) eunit
+
+clean:
+ @$(REBAR) clean
+
+force: ;
17 dev.config
@@ -0,0 +1,17 @@
+[
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ % Log-Machine section
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ {logmachine,
+ [
+ {evict_period, {5, sec} },
+ {instances, [
+ {error_logger, [ {dir, "./errlogs"},
+ {evict_after, {3, hour}},
+ {reopen_period, {30, min}},
+ {archive_after, {7, day}},
+ {locate_em, error_logger} ] }
+ ]
+ }
+ ]}
+].
10 ebin/logmachine.app
@@ -0,0 +1,10 @@
+%% -*- mode: erlang; -*-
+{application, logmachine,
+ [{description, "An Erlang Log Machine"},
+ {vsn, "0.0.1"},
+ {modules, []},
+ {registered, []},
+ {build_dependencies, []},
+ {env, []},
+ {applications, [kernel, stdlib, sasl]},
+ {mod, {logmachine_app, []}}]}.
12 include/log.hrl
@@ -0,0 +1,12 @@
+-define(SELF_APP, fun()->case application:get_application() of {ok,_App} -> _App; undefined -> undefined end end()).
+
+-define(LOG_INFO(Report), error_logger:info_report([Report, {application, ?SELF_APP}, {module, ?MODULE}, {line, ?LINE}])).
+-define(LOG_WARNING(Report), error_logger:warning_report([Report, {application, ?SELF_APP}, {module, ?MODULE}, {line, ?LINE}])).
+-define(LOG_ERROR(Report), error_logger:error_report([Report, {application, ?SELF_APP}, {module, ?MODULE}, {line, ?LINE}])).
+
+%% Echo macro for debugging purposes. Just a convenient helper to print something
+-ifdef(debug).
+-define(ECHO(Message), io:format("(~p|~p|~p): ~p~n", [self(),?MODULE, ?LINE, Message])).
+-else.
+-define(ECHO(Message), ok).
+-endif.
6 rebar.config
@@ -0,0 +1,6 @@
+{erl_opts, [warnings_as_errors, debug_info]}.
+{xref_checks, [undefined_function_calls]}.
+{dialyzer_opts, [{warnings, [unmatched_returns]}]}.
+
+{cover_enabled, true}.
+{clean_files, [".eunit", "ebin/*.beam"]}.
116 src/logmachine_app.erl
@@ -0,0 +1,116 @@
+%%%-------------------------------------------------------------------
+%%% @author <vjache@gmail.com>
+%%% @copyright (C) 2011, Vyacheslav Vorobyov. All Rights Reserved.
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% @doc
+%%% TODO: Document it.
+%%% @end
+%%% Created : Nov 05, 2011
+%%%-------------------------------------------------------------------------------
+-module(logmachine_app).
+
+-behaviour(application).
+%% --------------------------------------------------------------------
+%% Include files
+%% --------------------------------------------------------------------
+
+%% --------------------------------------------------------------------
+%% Behavioural exports
+%% --------------------------------------------------------------------
+-export([
+ start/2,
+ stop/1
+ ]).
+
+%% --------------------------------------------------------------------
+%% Internal exports
+%% --------------------------------------------------------------------
+-export([get_env/1, get_env/2, get_instance_env/2, get_instance_env/3]).
+
+%% --------------------------------------------------------------------
+%% Macros
+%% --------------------------------------------------------------------
+
+%% --------------------------------------------------------------------
+%% Records
+%% --------------------------------------------------------------------
+
+%% --------------------------------------------------------------------
+%% API Functions
+%% --------------------------------------------------------------------
+
+
+%% ====================================================================!
+%% External functions
+%% ====================================================================!
+%% --------------------------------------------------------------------
+%% Func: start/2
+%% Returns: {ok, Pid} |
+%% {ok, Pid, State} |
+%% {error, Reason}
+%% --------------------------------------------------------------------
+start(_Type, _StartArgs) ->
+ case logmachine_sup:start_link_main() of
+ {ok, Pid} ->
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+%% --------------------------------------------------------------------
+%% Func: stop/1
+%% Returns: any
+%% --------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+get_env(Env) ->
+ get_env(Env, fun()-> throw({noconf, Env}) end).
+get_env(Env, Default) ->
+ case application:get_env(logmachine, Env) of
+ undefined ->
+ if is_function(Default,0) -> Default();
+ true -> Default
+ end;
+ {ok,Val} ->
+ Val
+ end.
+
+get_instance_env(InstanceName, Env) ->
+ InstanceProps=get_instance_props(InstanceName),
+ case proplists:get_value(Env,InstanceProps) of
+ undefined -> get_env(Env);
+ Value -> Value
+ end.
+
+get_instance_env(InstanceName, Env, Default) ->
+ InstanceProps=get_instance_props(InstanceName),
+ case proplists:get_value(Env,InstanceProps) of
+ undefined -> get_env(Env, Default);
+ Value -> Value
+ end.
+
+get_instance_props(InstanceName) ->
+ case proplists:get_value(InstanceName, get_env(instances)) of
+ undefined -> throw({noconf_instance, InstanceName});
+ [{_,_}|_]=Props ->
+ Props;
+ BadProps ->
+ throw({badconf_instance, InstanceName, BadProps})
+ end.
+
+%% ====================================================================
+%% Internal functions
+%% ====================================================================
+
130 src/logmachine_cache_srv.erl
@@ -0,0 +1,130 @@
+%%%-------------------------------------------------------------------
+%%% @author <vjache@gmail.com>
+%%% @copyright (C) 2011, Vyacheslav Vorobyov. All Rights Reserved.
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% @doc
+%%% TODO: Document it.
+%%% @end
+%%% Created : Nov 05, 2011
+%%%-------------------------------------------------------------------------------
+-module(logmachine_cache_srv).
+
+-behaviour(gen_server).
+
+%% --------------------------------------------------------------------
+%% Include files
+%% --------------------------------------------------------------------
+
+-import(logmachine_util,[make_name/1,send_after/2,to_millis/1,now_to_millis/1,millis_to_now/1]).
+
+-define(ALARM_EVICT, {alarm,evict}).
+
+%% --------------------------------------------------------------------
+%% External exports
+-export([start_link_cache/1, start_link_evictor/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+-record(state_cache, {ets :: ets:tab()}).
+-record(state_evictor, {ets :: ets:tab(),evict_period,evict_after}).
+
+%% ====================================================================
+%% External functions
+%% ====================================================================
+
+start_link_cache(InstanceName) ->
+ SrvName=make_name([InstanceName, cache, srv]),
+ gen_server:start_link({local, SrvName}, ?MODULE, {cache,InstanceName}, []).
+
+start_link_evictor(InstanceName) ->
+ SrvName=make_name([InstanceName, evictor, srv]),
+ gen_server:start_link({local, SrvName}, ?MODULE, {evictor,InstanceName}, []).
+
+get_evict_period(InstanceName) ->
+ logmachine_app:get_instance_env(
+ InstanceName,
+ evict_period,
+ {5, sec}).
+
+get_evict_after(InstanceName) ->
+ logmachine_app:get_instance_env(
+ InstanceName,
+ evict_after,
+ {4, hour}).
+
+%% ====================================================================
+%% Server functions
+%% ====================================================================
+
+%% --------------------------------------------------------------------
+%% Function: init/1
+%% Description: Initiates the server
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% --------------------------------------------------------------------
+init({cache,InstanceName}) ->
+ % 1. Open ETS ordered table
+ InstanceEts=ets:new(make_name(InstanceName), [ordered_set, named_table, public, {keypos, 1}]),
+ {ok, #state_cache{ets=InstanceEts}};
+init({evictor,InstanceName}) ->
+ EvictPeriod=get_evict_period(InstanceName),
+ send_after(EvictPeriod, ?ALARM_EVICT),
+ {ok, #state_evictor{ets=make_name(InstanceName),
+ evict_period=EvictPeriod,
+ evict_after=get_evict_after(InstanceName)}}.
+
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(Msg, State) ->
+ handle_info(Msg, State).
+
+% Cache clauses
+handle_info({_,_}=Info, #state_cache{ets=Ets}=State) ->
+ ets:insert(Ets, Info),
+ {noreply, State};
+% Evictor clauses
+handle_info(?ALARM_EVICT, #state_evictor{ets=Ets,evict_after=EvictAfter,evict_period=EvictPeriod}=State) ->
+ Infimum=millis_to_now(now_to_millis(now()) - to_millis(EvictAfter)),
+ do_eviction(Ets,Infimum),
+ send_after(EvictPeriod, ?ALARM_EVICT),
+ {noreply, State};
+% Default clauses
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%% --------------------------------------------------------------------
+%%% Internal functions
+%% --------------------------------------------------------------------
+
+do_eviction(Ets, Infimum) ->
+ case ets:first(Ets) of
+ '$end_of_table' ->
+ ok;
+ K when K<Infimum ->
+ ets:delete(Ets, K),
+ do_eviction(Ets, Infimum);
+ _ ->
+ ok
+ end.
111 src/logmachine_emlocator_srv.erl
@@ -0,0 +1,111 @@
+%%%-------------------------------------------------------------------
+%%% @author <vjache@gmail.com>
+%%% @copyright (C) 2011, Vyacheslav Vorobyov. All Rights Reserved.
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% @doc
+%%% TODO: Document it.
+%%% @end
+%%% Created : Nov 06, 2011
+%%%-------------------------------------------------------------------------------
+-module(logmachine_emlocator_srv).
+
+-behaviour(gen_server).
+%% --------------------------------------------------------------------
+%% Include files
+%% --------------------------------------------------------------------
+
+%% --------------------------------------------------------------------
+%% External exports
+-export([start_link/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+-import(logmachine_util,[make_name/1]).
+
+-record(state, {em_name,instance}).
+
+%% ====================================================================
+%% External functions
+%% ====================================================================
+
+
+%% ====================================================================
+%% Server functions
+%% ====================================================================
+start_link(InstanceName) ->
+ SrvName=make_name([InstanceName, locator, srv]),
+ gen_server:start_link({local, SrvName}, ?MODULE, {locator,InstanceName}, []).
+
+%% --------------------------------------------------------------------
+%% Function: init/1
+%% Description: Initiates the server
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% --------------------------------------------------------------------
+init({locator, InstanceName}) ->
+ EventManagerName=logmachine_app:get_instance_env(InstanceName, locate_em, InstanceName),
+ erlang:process_flag(trap_exit, true),
+ install_event_handlers(node(),EventManagerName, InstanceName),
+ ok=net_kernel:monitor_nodes(true, [{node_type, visible}, nodedown_reason]),
+ {ok, #state{instance=InstanceName,em_name=EventManagerName}}.
+
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(Msg, State) ->
+ handle_info(Msg, State).
+
+handle_info({nodeup, Node, _InfoList}, #state{instance=InstanceName,em_name=EventManagerName}=State) ->
+ install_event_handlers(Node,EventManagerName, InstanceName),
+ {noreply, State};
+handle_info({nodedown, _Node, _InfoList}, State) ->
+ % Node down report
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%% --------------------------------------------------------------------
+%%% Internal functions
+%% --------------------------------------------------------------------
+install_event_handlers(Node, EventManagerName, InstanceName) ->
+ try gen_event:which_handlers({EventManagerName, Node}),
+ HandlerModule=logmachine_event_handler,
+ upload_module(Node, HandlerModule),
+ ok=gen_event:add_sup_handler(
+ {EventManagerName, Node}, % EventMgrRef
+ {HandlerModule, node()}, % Handler
+ logmachine_receiver_srv:get_global_alias(InstanceName)) % Args
+ catch _: noproc -> ok end.
+upload_module(Node, _Mod) when Node==node() ->
+ ok;
+upload_module(Node, Mod) ->
+ case code:get_object_code(Mod) of
+ {_Module, Bin, Fname} ->
+ case rpc:call(Node, code, load_binary, [Mod, Fname, Bin]) of
+ {error, Reason} -> throw({cant_upload_module, Node, Mod, Reason});
+ {badrpc, Reason} -> throw({cant_upload_module, Node, Mod, Reason});
+ {module, Mod} ->
+ ok
+ end;
+ error ->
+ throw({cant_upload_module, Node, Mod, {error, {'code:get_object_code', [Mod]}}})
+ end.
66 src/logmachine_event_handler.erl
@@ -0,0 +1,66 @@
+%%%-------------------------------------------------------------------
+%%% @author <vjache@gmail.com>
+%%% @copyright (C) 2011, Vyacheslav Vorobyov. All Rights Reserved.
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% @doc
+%%% TODO: Document it.
+%%% @end
+%%% Created : Nov 14, 2011
+%%%-------------------------------------------------------------------------------
+-module(logmachine_event_handler).
+
+-behaviour(gen_event).
+%% --------------------------------------------------------------------
+%% Include files
+%% --------------------------------------------------------------------
+
+%% --------------------------------------------------------------------
+%% External exports
+-export([]).
+
+%% gen_event callbacks
+-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
+
+-record(state, {receiver_global_alias}).
+
+%% ====================================================================
+%% External functions
+%% ====================================================================
+
+
+%% ====================================================================
+%% Server functions
+%% ====================================================================
+
+init(ReceiverGlobalAlias) ->
+ {ok, #state{receiver_global_alias=ReceiverGlobalAlias}}.
+
+handle_event(Event, #state{receiver_global_alias=ReceiverGlobalAlias}=State) ->
+ gen_server:cast({global, ReceiverGlobalAlias}, Event),
+ {ok, State}.
+
+handle_call(_Request, State) ->
+ Reply = ok,
+ {ok, Reply, State}.
+handle_info(_Info, State) ->
+ {ok, State}.
+terminate(_Reason, _State) ->
+ ok.
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%% --------------------------------------------------------------------
+%%% Internal functions
+%% --------------------------------------------------------------------
+
109 src/logmachine_receiver_srv.erl
@@ -0,0 +1,109 @@
+%%%-------------------------------------------------------------------
+%%% @author <vjache@gmail.com>
+%%% @copyright (C) 2011, Vyacheslav Vorobyov. All Rights Reserved.
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% @doc
+%%% TODO: Document it.
+%%% @end
+%%% Created : Nov 05, 2011
+%%%-------------------------------------------------------------------------------
+-module(logmachine_receiver_srv).
+
+-behaviour(gen_server).
+%% --------------------------------------------------------------------
+%% Include files
+%% --------------------------------------------------------------------
+
+%% --------------------------------------------------------------------
+%% External exports
+-export([start_link/1, get_global_alias/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+-import(logmachine_util,[make_name/1]).
+
+
+-record(state, {global_alias,cacher,recorder}).
+
+%% ====================================================================
+%% External functions
+%% ====================================================================
+
+start_link(InstanceName) ->
+ SrvName=make_name([InstanceName, receiver, srv]),
+ gen_server:start_link(
+ {local, SrvName},
+ ?MODULE, [InstanceName], []).
+
+get_global_alias(InstanceName) ->
+ SrvName=make_name([InstanceName, receiver, srv]),
+ case gen_server:call(SrvName, get_global_alias) of
+ {error, Reason} -> throw(Reason);
+ R -> R
+ end.
+
+allocate_global_name(BaseName, MaxAttempts) ->
+ allocate_global_name(BaseName, 0, MaxAttempts).
+allocate_global_name(BaseName, MaxAttempts, MaxAttempts) ->
+ throw({global_aliases_exhausted, BaseName, MaxAttempts});
+allocate_global_name(BaseName, N, MaxAttempts) ->
+ GlobalAlias={BaseName, N},
+ case global:register_name(
+ GlobalAlias, self(), fun global:random_notify_name/3) of
+ yes -> GlobalAlias;
+ no -> allocate_global_name(BaseName, N+1, MaxAttempts)
+ end.
+
+%% ====================================================================
+%% Server functions
+%% ====================================================================
+
+init([InstanceName]) ->
+ CacheSrvName=logmachine_util:make_name([InstanceName, cache, srv]),
+ RecorderSrvName=logmachine_util:make_name([InstanceName, recorder, srv]),
+ {ok, #state{global_alias=allocate_global_name(InstanceName, 10),
+ cacher=CacheSrvName,
+ recorder=RecorderSrvName}}.
+
+handle_call(get_global_alias, _From, #state{global_alias=GlbalAlias}=State) ->
+ {reply, GlbalAlias, State};
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(Info, #state{cacher=Cacher,recorder=Recorder}=State) ->
+ Timestamp=now(),
+ Event={Timestamp, Info},
+ gen_server:cast(Cacher, Event),
+ gen_server:cast(Recorder, Event),
+ {noreply, State}.
+
+handle_info({global_name_conflict, _Name},
+ #state{global_alias={InstanceName,_}}=State) ->
+ {noreply,
+ State#state{global_alias=allocate_global_name(InstanceName, 10)}};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%% --------------------------------------------------------------------
+%%% Internal functions
+%% --------------------------------------------------------------------
+
212 src/logmachine_recorder_srv.erl
@@ -0,0 +1,212 @@
+%%%-------------------------------------------------------------------
+%%% @author <vjache@gmail.com>
+%%% @copyright (C) 2011, Vyacheslav Vorobyov. All Rights Reserved.
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% @doc
+%%% TODO: Document it.
+%%% @end
+%%% Created : Nov 05, 2011
+%%%-------------------------------------------------------------------------------
+-module(logmachine_recorder_srv).
+
+-behaviour(gen_server).
+%% --------------------------------------------------------------------
+%% Include files
+%% --------------------------------------------------------------------
+
+-include("log.hrl").
+
+-import(logmachine_util,[make_name/1,send_after/2,to_millis/1,now_to_millis/1,millis_to_now/1,ensure_dir/1]).
+
+-define(ALARM_REOPEN, {alarm, reopen}).
+-define(ALARM_ARCHIVE, {alarm, archive}).
+
+%% --------------------------------------------------------------------
+%% External exports
+-export([start_link_archiver/1,start_link_recorder/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+-record(state_recorder, {instance_name, reopen_period, last_timestamp}).
+-record(state_archiver, {instance_name, archive_period, archive_after}).
+
+%% ====================================================================
+%% External functions
+%% ====================================================================
+
+start_link_recorder(InstanceName) ->
+ SrvName=make_name([InstanceName, recorder, srv]),
+ gen_server:start_link({local, SrvName}, ?MODULE, {recorder,InstanceName}, []).
+start_link_archiver(InstanceName) ->
+ SrvName=make_name([InstanceName, archiver, srv]),
+ gen_server:start_link({local, SrvName}, ?MODULE, {archiver, InstanceName}, []).
+%% ====================================================================
+%% Server functions
+%% ====================================================================
+
+get_data_dir(InstanceName) ->
+ logmachine_app:get_instance_env(
+ InstanceName,
+ dir,
+ fun() -> filename:join("./data", InstanceName) end).
+
+get_arch_data_dir(InstanceName) ->
+ logmachine_app:get_instance_env(
+ InstanceName,
+ arch_dir,
+ fun() -> filename:join(get_data_dir(InstanceName), "archive") end).
+
+get_log_file(InstanceName) ->
+ filename:join(get_data_dir(InstanceName), InstanceName)++".log".
+
+get_reopen_period(InstanceName) ->
+ logmachine_app:get_instance_env(
+ InstanceName,
+ reopen_period,
+ {30, min}).
+
+get_archive_period(InstanceName) ->
+ logmachine_app:get_instance_env(
+ InstanceName,
+ archive_period,
+ {60, min}).
+
+get_archive_after(InstanceName) ->
+ logmachine_app:get_instance_env(
+ InstanceName,
+ archive_after,
+ {7, day}).
+
+% Init recorder
+init({recorder,InstanceName}) ->
+ ensure_dir(get_data_dir(InstanceName)),
+ open_disk_log(InstanceName),
+ ReoPeriod=get_reopen_period(InstanceName),
+ send_after(ReoPeriod, ?ALARM_REOPEN),
+ {ok, #state_recorder{instance_name=InstanceName,reopen_period=ReoPeriod}};
+% Init archiver
+init({archiver,InstanceName}) ->
+ ensure_dir(get_arch_data_dir(InstanceName)),
+ ArchPeriod=get_archive_period(InstanceName),
+ ArchAfter=get_archive_after(InstanceName),
+ send_after(ArchPeriod, ?ALARM_ARCHIVE),
+ {ok, #state_archiver{instance_name=InstanceName,archive_period=ArchPeriod,archive_after=ArchAfter}}.
+
+open_disk_log(InstanceName) ->
+ LogFile=get_log_file(InstanceName),
+ case disk_log:open([{name,InstanceName}, {file, LogFile}]) of
+ {ok,_} ->
+ ok;
+ {repaired,_,
+ {recovered, _},
+ {badbytes, _}} ->
+ ok;
+ {error, Reason} ->
+ throw(Reason)
+ end.
+
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(Msg, State) ->
+ handle_info(Msg, State).
+
+% Recorder clauses
+handle_info(?ALARM_REOPEN, #state_recorder{instance_name=Name,reopen_period=ReoPeriod,last_timestamp=Timestamp}=State) ->
+ do_reopen(Name,Timestamp),
+ send_after(ReoPeriod, ?ALARM_REOPEN),
+ {noreply, State};
+handle_info({Timestamp,_Data}=Event, #state_recorder{instance_name=Name}=State) ->
+ ok=disk_log:alog(Name, Event),
+ {noreply, State #state_recorder{last_timestamp=Timestamp} };
+% Archiver clauses
+handle_info(?ALARM_ARCHIVE,
+ #state_archiver{instance_name=Name,
+ archive_period=ArchPeriod,
+ archive_after=ArchAfter}=State) ->
+ do_archive(Name, ArchAfter),
+ send_after(ArchPeriod, ?ALARM_ARCHIVE),
+ {noreply, State};
+% Universal clauses
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%% --------------------------------------------------------------------
+%%% Internal functions
+%% --------------------------------------------------------------------
+
+do_archive(InstanceName, ArchAfter) ->
+ InfimumMillis=now_to_millis(now()) - to_millis(ArchAfter),
+ try do_move(InstanceName,InfimumMillis)
+ catch _:Reason1 -> ?LOG_ERROR([{move_failed,Reason1}, {stacktrace, erlang:get_stacktrace()}]) end,
+ try do_zip(InstanceName)
+ catch _:Reason2 -> ?LOG_ERROR([{zip_failed,Reason2}, {stacktrace, erlang:get_stacktrace()}]) end.
+
+do_move(InstanceName,InfimumMillis) ->
+ ArchDir=get_arch_data_dir(InstanceName),
+ LogDir=get_data_dir(InstanceName),
+ DateTime=calendar:now_to_universal_time(millis_to_now(InfimumMillis)),
+ PseudoFilename=reopened_filename(InstanceName,DateTime,InfimumMillis rem 1000),
+ case filelib:wildcard(get_wildcard(InstanceName), LogDir) of
+ [] -> ok;
+ Files ->
+ AFiles=lists:takewhile(
+ fun(E)-> PseudoFilename > E end,
+ lists:sort(Files)),
+ [begin
+ NewAFile=filename:join(ArchDir,filename:basename(AFile)),
+ ok=file:rename(AFile, NewAFile)
+ end ||AFile <- [filename:join(LogDir,FN)|| FN <- AFiles]],
+ ok
+ end.
+
+do_zip(InstanceName) ->
+ ArchDir=get_arch_data_dir(InstanceName),
+ [begin
+ File=filename:join(ArchDir,FN),
+ ZipAFile=File++".zip",
+ case filelib:is_regular(ZipAFile) of
+ false ->
+ {ok,_}=zip:create(ZipAFile, [FN], [{cwd,ArchDir}]);
+ _ ->
+ ok
+ end,
+ file:delete(File)
+ end || FN <- filelib:wildcard(get_wildcard(InstanceName), ArchDir),
+ filename:extension(FN)=/=".zip"],
+ ok.
+
+do_reopen(InstanceName, undefined) ->
+ do_reopen(InstanceName, now()); %TODO: read log for last timestamp instead of now()
+do_reopen(InstanceName, {_,_,Micros}=Timestamp) ->
+ DateTime=calendar:now_to_universal_time(Timestamp),
+ Filename=filename:join(
+ get_data_dir(InstanceName),
+ reopened_filename(InstanceName, DateTime, Micros div 1000)),
+ ok=disk_log:reopen(InstanceName, Filename).
+
+get_wildcard(InstanceName) ->
+ lists:flatten(io_lib:format("~p_????-??-??_*", [InstanceName])).
+reopened_filename(InstanceName, {{Y,Mon,D},{H,Min,S}}, Millis) ->
+ lists:flatten(io_lib:format(
+ "~p_~.4.0w-~.2.0w-~.2.0w_~.2.0w-~.2.0w-~.2.0w.~.3.0wZ",
+ [InstanceName, Y, Mon, D, H, Min, S, Millis])).
119 src/logmachine_sup.erl
@@ -0,0 +1,119 @@
+%%%-------------------------------------------------------------------
+%%% @author <vjache@gmail.com>
+%%% @copyright (C) 2011, Vyacheslav Vorobyov. All Rights Reserved.
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% @doc
+%%% TODO: Document it.
+%%% @end
+%%% Created : Nov 05, 2011
+%%%-------------------------------------------------------------------------------
+-module(logmachine_sup).
+
+-behaviour(supervisor).
+%% --------------------------------------------------------------------
+%% Include files
+%% --------------------------------------------------------------------
+
+%% --------------------------------------------------------------------
+%% External exports
+%% --------------------------------------------------------------------
+-export([start_link_main/0, start_link_instance/1,start_link_component/2]).
+
+%% --------------------------------------------------------------------
+%% Internal exports
+%% --------------------------------------------------------------------
+-export([
+ init/1
+ ]).
+
+%% --------------------------------------------------------------------
+%% Macros
+%% --------------------------------------------------------------------
+-define(SERVER, ?MODULE).
+
+%% --------------------------------------------------------------------
+%% Records
+%% --------------------------------------------------------------------
+
+%% ====================================================================
+%% External functions
+%% ====================================================================
+
+start_link_main() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, root).
+
+start_link_instance(InstanceName) ->
+ SupName=logmachine_util:make_name([InstanceName,sup]),
+ supervisor:start_link({local, SupName}, ?MODULE, {instance, InstanceName}).
+
+start_link_component(ComponentName, InstanceName) ->
+ SupName=logmachine_util:make_name([InstanceName,ComponentName,sup]),
+ supervisor:start_link({local, SupName}, ?MODULE, {component, ComponentName, InstanceName}).
+
+%% ====================================================================
+%% Server functions
+%% ====================================================================
+%% --------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, {SupFlags, [ChildSpec]}} |
+%% ignore |
+%% {error, Reason}
+%% --------------------------------------------------------------------
+% Root supervisor
+init(root) ->
+ Instances=logmachine_app:get_env(instances,[]),
+ InstancesSups=
+ [{InstanceName,
+ {?MODULE,start_link_instance,[InstanceName]},
+ permanent, infinity, supervisor,[?MODULE]} || InstanceName <- proplists:get_keys(Instances)],
+ {ok,{{one_for_one,0,1}, InstancesSups}};
+% Instance supervisor
+init({instance, InstanceName}) ->
+ Components=[recorder, cache], % logmachine_receiver_srv
+ ComponentsSups=
+ [{Component,
+ {?MODULE,start_link_component,[Component,InstanceName]},
+ permanent, infinity, supervisor, [?MODULE]}|| Component <- Components],
+ Receiver={logmachine_receiver_srv,
+ {logmachine_receiver_srv,start_link,[InstanceName]},
+ permanent, 10000, worker, [logmachine_receiver_srv]},
+ Locator={logmachine_emlocator_srv,
+ {logmachine_emlocator_srv,start_link,[InstanceName]},
+ permanent, 10000, worker, [logmachine_emlocator_srv]},
+ {ok,{{one_for_one,0,1}, ComponentsSups ++ [Receiver,Locator]}};
+% Recorder supervisor
+init({component, recorder, InstanceName}) ->
+ Mod=logmachine_recorder_srv,
+ Recorder={logmachine_recorder,
+ {Mod,start_link_recorder,[InstanceName]},
+ permanent, 10000, worker, [Mod]},
+ Archiver={'logmachine_recorder/archiver',
+ {Mod,start_link_archiver,[InstanceName]},
+ permanent, 10000, worker, [Mod]},
+ {ok,{{one_for_one,0,1}, [Recorder, Archiver]}};
+% Cache supervisor
+init({component, cache, InstanceName}) ->
+ Mod=logmachine_cache_srv,
+ Cache={logmachine_cache,
+ {Mod,start_link_cache,[InstanceName]},
+ permanent, 10000, worker, [Mod]},
+ Evictor={'logmachine_cache/evictor',
+ {Mod,start_link_evictor,[InstanceName]},
+ permanent, 10000, worker, [Mod]},
+ {ok,{{one_for_one,0,1}, [Cache, Evictor]}}.
+
+%% ====================================================================
+%% Internal functions
+%% ====================================================================
+
74 src/logmachine_util.erl
@@ -0,0 +1,74 @@
+%%%-------------------------------------------------------------------
+%%% @author <vjache@gmail.com>
+%%% @copyright (C) 2011, Vyacheslav Vorobyov. All Rights Reserved.
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% @doc
+%%% TODO: Document it.
+%%% @end
+%%% Created : Nov 05, 2011
+%%%-------------------------------------------------------------------------------
+-module(logmachine_util).
+
+%%
+%% Include files
+%%
+
+%%
+%% Exported Functions
+%%
+-export([make_name/1, to_millis/1, now_to_millis/1,millis_to_now/1, send_after/2, ensure_dir/1]).
+
+%%
+%% API Functions
+%%
+
+ensure_dir(Dir) ->
+ case filelib:ensure_dir(filename:join(Dir, "fake")) of
+ ok -> Dir;
+ {error, Reason} -> throw(Reason)
+ end.
+
+make_name(NameComponent) when is_atom(NameComponent) ->
+ NameComponent;
+make_name([H|_]=NameComponents) when is_atom(H) ->
+ list_to_atom(lists:flatten(([io_lib:format(".~p", [Comp]) || Comp <- NameComponents])));
+make_name(String) when is_list(String) ->
+ list_to_atom(String).
+
+now_to_millis({MegaS,S,MicroS}) ->
+ MegaS*1000*1000*1000 + S*1000 + MicroS div 1000.
+
+millis_to_now(Millis) ->
+ {Millis div 1000000000,
+ (Millis rem 1000000000) div 1000,
+ (Millis rem 1000)*1000}.
+
+to_millis({N,sec}) ->
+ timer:seconds(N);
+to_millis({N,min}) ->
+ timer:minutes(N);
+to_millis({N,hour}) ->
+ timer:hours(N);
+to_millis({N,day}) ->
+ N*timer:hours(24);
+to_millis({N,hms}) ->
+ timer:hms(N).
+
+send_after(Period, Message) ->
+ {ok,_}=timer:send_after(to_millis(Period), Message).
+
+%%
+%% Local Functions
+%%
+
1  start.bat
@@ -0,0 +1 @@
+werl -args_file "vm.args" -name lm@some.host.name -config dev.config -eval "application:start(logmachine)"
6 vm.args
@@ -0,0 +1,6 @@
+-boot start_sasl
+
+-pa ebin
+
+## Cookie for distributed erlang
+-setcookie "QWE123"
Please sign in to comment.
Something went wrong with that request. Please try again.