2 %% Copyright (C) 2006 Damien Katz
4 %% This program is free software; you can redistribute it and/or
5 %% modify it under the terms of the GNU General Public License
6 %% as published by the Free Software Foundation; either version 2
7 %% of the License, or (at your option) any later version.
9 %% This program is distributed in the hope that it will be useful,
10 %% but WITHOUT ANY WARRANTY; without even the implied warranty of
11 %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 %% GNU General Public License for more details.
14 %% You should have received a copy of the GNU General Public License
15 %% along with this program; if not, write to the Free Software
16 %% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 -behaviour(gen_event
).
21 -export([start
/2, stop
/0]).
22 -export([error
/1,error
/2,info
/1,info
/2,debug
/1,debug
/2]).
23 -export([init
/1, handle_event
/2, terminate
/2, code_change
/3, handle_info
/2, handle_call
/2]).
25 -define(LEVEL_ERROR
, 3).
26 -define(LEVEL_INFO
, 2).
27 -define(LEVEL_DEBUG
, 1).
28 -define(LEVEL_TMI
, 0).
30 level_integer(error
) -> ?LEVEL_ERROR
;
31 level_integer(info
) -> ?LEVEL_INFO
;
32 level_integer(debug
) -> ?LEVEL_DEBUG
;
33 level_integer(tmi
) -> ?LEVEL_TMI
;
34 level_integer(_Else
) -> ?LEVEL_ERROR
. % anything else default to ERROR level
37 start(Filename
, Level
) ->
38 % delete first so we don't wind up with multiple if called multiple times
39 % (happens during debugging)
40 error_logger:delete_report_handler(couch_log
),
41 error_logger:add_report_handler(couch_log
, {Filename
, Level
}).
44 error_logger:delete_report_handler(couch_log
).
46 init({Filename
, Level
}) ->
47 {ok
, Fd
} = file:open(Filename
, [append
]),
48 {ok
, {Fd
, level_integer(Level
)}}.
50 get_level_integer() ->
51 catch gen_event:call(error_logger
, couch_log
, get_level_integer
).
56 error(Format
, Args
) ->
57 error_logger:error_report(couch_error
, {Format
, Args
}).
63 case get_level_integer() =< ?LEVEL_INFO
of
65 error_logger:info_report(couch_info
, {Format
, Args
});
73 debug(Format
, Args
) ->
74 case get_level_integer() =< ?LEVEL_DEBUG
of
76 error_logger:info_report(couch_debug
, {Format
, Args
});
81 handle_event({error_report
, _
, {Pid
, couch_error
, {Format
, Args
}}}, {Fd
, _LogLevel
}=State
) ->
82 log(Fd
, Pid
, error
, Format
, Args
),
84 handle_event({error_report
, _
, {Pid
, _
, _
}}=Event
, {Fd
, _LogLevel
}=State
) ->
85 log(Fd
, Pid
, error
, "~p", [Event
]),
87 handle_event({error
, _
, {Pid
, Format
, Args
}}, {Fd
, _LogLevel
}=State
) ->
88 log(Fd
, Pid
, error
, Format
, Args
),
90 handle_event({info_report
, _
, {Pid
, couch_info
, {Format
, Args
}}}, {Fd
, LogLevel
}=State
)
91 when LogLevel
=< ?LEVEL_INFO
->
92 log(Fd
, Pid
, info
, Format
, Args
),
94 handle_event({info_report
, _
, {Pid
, couch_debug
, {Format
, Args
}}}, {Fd
, LogLevel
}=State
)
95 when LogLevel
=< ?LEVEL_DEBUG
->
96 log(Fd
, Pid
, debug
, Format
, Args
),
98 handle_event({_
, _
, {Pid
, _
, _
}}=Event
, {Fd
, LogLevel
}=State
)
99 when LogLevel
=< ?LEVEL_TMI
->
100 % log every remaining event if tmi!
101 log(Fd
, Pid
, tmi
, "~p", [Event
]),
103 handle_event(_Event
, State
) ->
106 handle_call(get_level_integer
, {_Fd
, LogLevel
}=State
) ->
107 {ok
, LogLevel
, State
}.
109 handle_info(_Info
, State
) ->
112 code_change(_OldVsn
, State
, _Extra
) ->
115 terminate(_Arg
, {Fd
, _LoggingLevel
}) ->
118 log(Fd
, Pid
, Level
, Format
, Args
) ->
119 case (catch log_guts(Fd
, Pid
, Level
, Format
, Args
)) of
122 ErrorFormat
= "\r~n***************** ERROR OCCURED DURING LOGGING: *****************\r~n~p\r~n",
123 io:format(ErrorFormat
, [Error
]),
124 io:format(Fd
, ErrorFormat
, [Error
])
127 log_guts(Fd
, Pid
, Level
, Format
, Args
) ->
128 Msg
= io_lib:format(Format
, Args
),
129 ok
= io:format("[~s] [~p] ~s~n", [Level
, Pid
, Msg
]), % dump to console too
130 {ok
, Msg2
, _
} = regexp:gsub(lists:flatten(Msg
),"\\r\\n|\\r|\\n", "\r\n"),
131 ok
= io:format(Fd
, "[~s] [~s] [~p] ~s\r~n\r~n", [httpd_util:rfc1123_date(), Level
, Pid
, Msg2
]).