Updated Branches: refs/heads/import [created] 2d5628040
Initial commit Project: http://git-wip-us.apache.org/repos/asf/couchdb-twig/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-twig/commit/b06981fb Tree: http://git-wip-us.apache.org/repos/asf/couchdb-twig/tree/b06981fb Diff: http://git-wip-us.apache.org/repos/asf/couchdb-twig/diff/b06981fb Branch: refs/heads/import Commit: b06981fbde6d8e4a65cbf974020279b792ee38bb Parents: Author: Adam Kocoloski <[email protected]> Authored: Tue Mar 8 13:16:19 2011 -0500 Committer: Adam Kocoloski <[email protected]> Committed: Tue Mar 8 13:16:19 2011 -0500 ---------------------------------------------------------------------- .gitignore | 2 + rebar | Bin 0 -> 101028 bytes src/twig.app.src | 8 +++ src/twig.erl | 78 +++++++++++++++++++++ src/twig_app.erl | 21 ++++++ src/twig_event_handler.erl | 147 ++++++++++++++++++++++++++++++++++++++++ src/twig_int.hrl | 23 +++++++ src/twig_monitor.erl | 45 ++++++++++++ src/twig_sup.erl | 24 +++++++ src/twig_util.erl | 58 ++++++++++++++++ 10 files changed, 406 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f8ab87d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +ebin +src/.*.swp http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/rebar ---------------------------------------------------------------------- diff --git a/rebar b/rebar new file mode 100755 index 0000000..1f55c73 Binary files /dev/null and b/rebar differ http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/src/twig.app.src ---------------------------------------------------------------------- diff --git a/src/twig.app.src b/src/twig.app.src new file mode 100644 index 0000000..7e1da74 --- /dev/null +++ b/src/twig.app.src @@ -0,0 +1,8 @@ +{application, twig, [ + {description, "Logger"}, + {vsn, git}, + {registered, []}, + {applications, [kernel, stdlib]}, + {mod, {twig_app, []}}, + {env, []} +]}. http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/src/twig.erl ---------------------------------------------------------------------- diff --git a/src/twig.erl b/src/twig.erl new file mode 100644 index 0000000..a3a9c58 --- /dev/null +++ b/src/twig.erl @@ -0,0 +1,78 @@ +% 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. + +-module(twig). + +-export([debug/1, info/1, notice/1, warn/1, err/1, crit/1, alert/1, emerg/1, + debug/2, info/2, notice/2, warn/2, err/2, crit/2, alert/2, emerg/2, + debug/3, info/3, notice/3, warn/3, err/3, crit/3, alert/3, emerg/3]). + +-export([set_level/1]). + +-include("twig_int.hrl"). + +debug(Format) -> log(debug, Format, [], []). +debug(Format, Data) -> log(debug, Format, Data, []). +debug(Format, Data, Options) -> log(debug, Format, Data, Options). + +info(Format) -> log(info, Format, [], []). +info(Format, Data) -> log(info, Format, Data, []). +info(Format, Data, Options) -> log(info, Format, Data, Options). + +notice(Format) -> log(notice, Format, [], []). +notice(Format, Data) -> log(notice, Format, Data, []). +notice(Format, Data, Options) -> log(notice, Format, Data, Options). + +warn(Format) -> log(warn, Format, [], []). +warn(Format, Data) -> log(warn, Format, Data, []). +warn(Format, Data, Options) -> log(warn, Format, Data, Options). + +err(Format) -> log(err, Format, [], []). +err(Format, Data) -> log(err, Format, Data, []). +err(Format, Data, Options) -> log(err, Format, Data, Options). + +crit(Format) -> log(crit, Format, [], []). +crit(Format, Data) -> log(crit, Format, Data, []). +crit(Format, Data, Options) -> log(crit, Format, Data, Options). + +alert(Format) -> log(alert, Format, [], []). +alert(Format, Data) -> log(alert, Format, Data, []). +alert(Format, Data, Options) -> log(alert, Format, Data, Options). + +emerg(Format) -> log(emerg, Format, [], []). +emerg(Format, Data) -> log(emerg, Format, Data, []). +emerg(Format, Data, Options) -> log(emerg, Format, Data, Options). + +set_level(LevelAtom) -> + application:set_env(twig, {level, twig_util:level(LevelAtom)}). + +%% internal + +log(LevelAtom, Format, Data, _Options) -> + %% TODO do something useful with options + Level = twig_util:level(LevelAtom), + case application:get_env(twig, level) of + {ok, Threshold} when Level =< Threshold -> + send_message(Level, Format, Data); + undefined when Level =< ?LEVEL_INFO -> + send_message(Level, Format, Data); + _ -> + ok + end. + +send_message(Level, Format, Data) -> + gen_event:sync_notify(error_logger, format(Level, Format, Data)). + +format(Level, Format, Data) -> + %% TODO truncate large messages + {twig, Level, iolist_to_binary(io_lib:format(Format, Data))}. + http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/src/twig_app.erl ---------------------------------------------------------------------- diff --git a/src/twig_app.erl b/src/twig_app.erl new file mode 100644 index 0000000..e16ad58 --- /dev/null +++ b/src/twig_app.erl @@ -0,0 +1,21 @@ +% 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. + +-module(twig_app). +-behaviour(application). +-export([start/2, stop/1]). + +start(_StartType, _StartArgs) -> + twig_sup:start_link(). + +stop(_State) -> + ok. http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/src/twig_event_handler.erl ---------------------------------------------------------------------- diff --git a/src/twig_event_handler.erl b/src/twig_event_handler.erl new file mode 100644 index 0000000..874789c --- /dev/null +++ b/src/twig_event_handler.erl @@ -0,0 +1,147 @@ +% 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. + +-module(twig_event_handler). + +-behaviour(gen_event). + +-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, + code_change/3]). + +-record(state, { + socket, + host, + port, + hostname, + os_pid, + appid, + facility, + level +}). + +-include("twig_int.hrl"). + +init([]) -> + {ok, Socket} = gen_udp:open(0), + {ok, ok, State} = handle_call(load_config, #state{socket=Socket}), + {ok, State}. + +handle_event({twig, Level, Msg}, State) -> + write(Level, Msg, State), + {ok, State}; + +% OTP standard events +handle_event({Class, _GL, {Pid, Format, Args}}, #state{level=Max} = State) -> + case otp_event_level(Class, Format) of + undefined -> + {ok, State}; + Level when Level > Max -> + {ok, State}; + Level -> + write(Level, message(Pid, Format, Args), State), + {ok, State} + end; + +handle_event(_Event, State) -> + {ok, State}. + +handle_call({set_level, Level}, State) -> + {ok, ok, State#state{level = Level}}; + +handle_call(load_config, State) -> + Host = case inet:getaddr(get_env(host, undefined), inet) of + {ok, Address} -> + Address; + {error, _} -> + undefined + end, + NewState = State#state{ + host = Host, + port = get_env(port, 514), + hostname = net_adm:localhost(), + os_pid = os:getpid(), + appid = get_env(appid, "bigcouch"), + facility = twig_util:facility(get_env(facility, local2)), + level = twig_util:level(get_env(level, info)) + }, + {ok, ok, NewState}; + +handle_call(_Call, State) -> + {ok, ignored, State}. + +handle_info(_Info, State) -> + {ok, State}. + +terminate(_Reason, State) -> + gen_udp:close(State#state.socket). + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +get_env(Key, Default) -> + case application:get_env(twig, Key) of + {ok, Value} -> + Value; + undefined -> + Default + end. + +write(_, _, #state{host=undefined}) -> + ok; +write(Level, Msg, State) when is_list(Msg); is_binary(Msg) -> + #state{facility=Facil, appid=App, hostname=Hostname, host=Host, port=Port, + socket=Socket, os_pid=OsPid} = State, + Pre = io_lib:format("<~B>~B ~s ~s ~s ~s - - ", [Facil bor Level, + ?SYSLOG_VERSION, twig_util:iso8601_timestamp(), Hostname, App, OsPid]), + %% TODO truncate large messages + gen_udp:send(Socket, Host, Port, [Pre, Msg, $\n]); +write(Level, {Format0, Args0}, State) -> + #state{facility=Facil, appid=App, hostname=Hostname, host=Host, port=Port, + socket=Socket, os_pid=OsPid} = State, + Format = "<~B>~B ~s ~s ~s ~s - - " ++ Format0 ++ "\n", + Args = [Facil bor Level, ?SYSLOG_VERSION, twig_util:iso8601_timestamp(), + Hostname, App, OsPid | Args0], + %% TODO truncate large messages + Packet = io_lib:format(Format, Args), + gen_udp:send(Socket, Host, Port, Packet). + +message(_Pid, crash_report, Report) -> + proc_lib:format(Report); +message(Pid, supervisor_report, Report) -> + Name = lists:keyfind(supervisor, 1, Report), + Error = lists:keyfind(errorContext, Report), + Reason = lists:keyfind(reason, 1, Report), + Offender = lists:keyfind(offender, 1, Report), + ChildPid = lists:keyfind(pid, 1, Offender), + ChildName = lists:keyfind(name, 1, Offender), + {M,F,_} = lists:keyfind(mfa, 1, Offender), + {"[~p] SUPERVISOR REPORT ~p ~p (~p) child: ~p [~p] ~p:~p", + [Pid, Name, Error, Reason, ChildName, ChildPid, M, F]}; +message(Pid, progress_report, Report) -> + {"[~p] PROGRESS REPORT~n~p", [Pid, Report]}; +message(Pid, Type, Report) when Type == std_error; + Type == std_info; + Type == std_warning -> + {"[~p] ~p: ~p", [Pid, Type, Report]}; +message(Pid, Format, Args) -> + {"[~p] " ++ Format, [Pid|Args]}. + +otp_event_level(error, _) -> ?LEVEL_ERR; +otp_event_level(warning_msg, _) -> ?LEVEL_WARN; +otp_event_level(info_msg, _) -> ?LEVEL_INFO; +otp_event_level(_, {_, crash_report, _}) -> ?LEVEL_CRIT; +otp_event_level(_, {_, supervisor_report, _}) -> ?LEVEL_WARN; +otp_event_level(_, {_, progress_report, _}) -> ?LEVEL_DEBUG; +otp_event_level(error_report, _) -> ?LEVEL_ERR; +otp_event_level(warning_report, _) -> ?LEVEL_WARN; +otp_event_level(info_report, _) -> ?LEVEL_INFO; +otp_event_level(_, _) -> undefined. http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/src/twig_int.hrl ---------------------------------------------------------------------- diff --git a/src/twig_int.hrl b/src/twig_int.hrl new file mode 100644 index 0000000..27f66ad --- /dev/null +++ b/src/twig_int.hrl @@ -0,0 +1,23 @@ +% 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. + +-define(SYSLOG_VERSION, 1). + +-define(LEVEL_DEBUG, 7). +-define(LEVEL_INFO, 6). +-define(LEVEL_NOTICE, 5). +-define(LEVEL_WARN, 4). +-define(LEVEL_ERR, 3). +-define(LEVEL_CRIT, 2). +-define(LEVEL_ALERT, 1). +-define(LEVEL_EMERG, 0). + http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/src/twig_monitor.erl ---------------------------------------------------------------------- diff --git a/src/twig_monitor.erl b/src/twig_monitor.erl new file mode 100644 index 0000000..5a4f86c --- /dev/null +++ b/src/twig_monitor.erl @@ -0,0 +1,45 @@ +% 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. + +-module(twig_monitor). + +-behaviour(gen_server). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). + +-export([start_link/0]). + +start_link() -> + gen_server:start_link(?MODULE, [], []). + +init(_) -> + gen_event:add_sup_handler(error_logger, twig_event_handler, []). + +handle_call(_Call, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Cast, State) -> + {noreply, State}. + +handle_info({gen_event_EXIT, twig_event_handler, Reason} = Msg, State) -> + io:format("~p~n", [Msg]), + {stop, Reason, State}; + +handle_info(_Msg, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_, State, _) -> + {ok, State}. http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/src/twig_sup.erl ---------------------------------------------------------------------- diff --git a/src/twig_sup.erl b/src/twig_sup.erl new file mode 100644 index 0000000..dc9aa13 --- /dev/null +++ b/src/twig_sup.erl @@ -0,0 +1,24 @@ +% 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. + +-module(twig_sup). +-behaviour(supervisor). +-export([start_link/0, init/1]). + +%% Helper macro for declaring children of supervisor +-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + {ok, { {one_for_one, 5, 10}, [?CHILD(twig_monitor, gen_server)]} }. http://git-wip-us.apache.org/repos/asf/couchdb-twig/blob/b06981fb/src/twig_util.erl ---------------------------------------------------------------------- diff --git a/src/twig_util.erl b/src/twig_util.erl new file mode 100644 index 0000000..19ec802 --- /dev/null +++ b/src/twig_util.erl @@ -0,0 +1,58 @@ +% 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. + +-module(twig_util). + +-export([level/1, facility/1, iso8601_timestamp/0]). + +level(debug) -> 7; +level(info) -> 6; +level(notice) -> 5; +level(warn) -> 4; +level(err) -> 3; +level(crit) -> 2; +level(alert) -> 1; +level(emerg) -> 0; + +level(I) when is_integer(I), I >= 0, I =< 7 -> + I; +level(_BadLevel) -> + 3. + +facility(kern) -> (0 bsl 3) ; % kernel messages +facility(user) -> (1 bsl 3) ; % random user-level messages +facility(mail) -> (2 bsl 3) ; % mail system +facility(daemon) -> (3 bsl 3) ; % system daemons +facility(auth) -> (4 bsl 3) ; % security/authorization messages +facility(syslog) -> (5 bsl 3) ; % messages generated internally by syslogd +facility(lpr) -> (6 bsl 3) ; % line printer subsystem +facility(news) -> (7 bsl 3) ; % network news subsystem +facility(uucp) -> (8 bsl 3) ; % UUCP subsystem +facility(cron) -> (9 bsl 3) ; % clock daemon +facility(authpriv) -> (10 bsl 3); % security/authorization messages (private) +facility(ftp) -> (11 bsl 3); % ftp daemon + +facility(local0) -> (16 bsl 3); +facility(local1) -> (17 bsl 3); +facility(local2) -> (18 bsl 3); +facility(local3) -> (19 bsl 3); +facility(local4) -> (20 bsl 3); +facility(local5) -> (21 bsl 3); +facility(local6) -> (22 bsl 3); +facility(local7) -> (23 bsl 3). + + +iso8601_timestamp() -> + {_,_,Micro} = Now = os:timestamp(), + {{Year,Month,Date},{Hour,Minute,Second}} = calendar:now_to_datetime(Now), + Format = "~4.10.0B-~2.10.0B-~2.10.0BT~2.10.0B:~2.10.0B:~2.10.0B.~6.10.0BZ", + io_lib:format(Format, [Year, Month, Date, Hour, Minute, Second, Micro]).
