diff options
-rw-r--r-- | src/ldapsp_app.erl | 2 | ||||
-rw-r--r-- | src/ldapsp_error_log_handler.erl | 160 |
2 files changed, 161 insertions, 1 deletions
diff --git a/src/ldapsp_app.erl b/src/ldapsp_app.erl index cdc6a22..60cde79 100644 --- a/src/ldapsp_app.erl +++ b/src/ldapsp_app.erl @@ -26,7 +26,7 @@ start(_Type, _StartArgs) -> LogHandlers = [{webmachine_access_log_handler, ["priv/log"]}, - {webmachine_error_log_handler, ["priv/log"]}], + {ldapsp_error_log_handler, ["priv/log"]}], application:set_env(webmachine, log_handlers, LogHandlers), % Evil hack so we reprocess the app config webmachine:stop(), diff --git a/src/ldapsp_error_log_handler.erl b/src/ldapsp_error_log_handler.erl new file mode 100644 index 0000000..f7825ea --- /dev/null +++ b/src/ldapsp_error_log_handler.erl @@ -0,0 +1,160 @@ +%%----------------------------------------------------------------------- +%% Copyright (c) 2017 Guido Günther +%% +%% This file is provided to you 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. +%% +%% based on error_log_handler.erl +%% Copyright (c) 2011-2014 Basho Technologies, Inc. All Rights Reserved. +%%----------------------------------------------------------------------- + +%% @doc Log handler for ldapsp + +-module(ldapsp_error_log_handler). + +-behaviour(gen_event). + +%% gen_event callbacks +-export([init/1, + handle_call/2, + handle_event/2, + handle_info/2, + terminate/2, + code_change/3]). + +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. + +-record(state, {filename, handle}). + +-define(FILENAME, "ldapsp_error.log"). + +%% =================================================================== +%% gen_event callbacks +%% =================================================================== + +%% @private +init([BaseDir]) -> + {ok,_} = webmachine_log:defer_refresh(?MODULE), + FileName = filename:join(BaseDir, ?FILENAME), + Handle = log_open(FileName), + {ok, #state{filename=FileName, handle=Handle}}. + +%% @private +handle_call({_Label, MRef, get_modules}, State) -> + {ok, {MRef, [?MODULE]}, State}; +handle_call({refresh, _Time}, State) -> + NewHandle = maybe_reopen(?MODULE, + State#state.filename, + State#state.handle), + {ok, ok, State#state{handle=NewHandle}}; +handle_call(_Request, State) -> + {ok, ok, State}. + +%% @private +handle_event({log_error, Msg}, State) -> + NewHandle = maybe_reopen(?MODULE, + State#state.filename, + State#state.handle), + NewState = State#state{handle=NewHandle}, + FormattedMsg = format_req(error, undefined, undefined, Msg), + _ = webmachine_log:log_write(State#state.handle, FormattedMsg), + {ok, NewState}; +handle_event({log_error, Code, _Req, _Reason}, State) when Code < 500 -> + {ok, State}; +handle_event({log_error, Code, Req, Reason}, State) -> + NewHandle = maybe_reopen(?MODULE, + State#state.filename, + State#state.handle), + NewState = State#state{handle=NewHandle}, + Msg = format_req(error, Code, Req, Reason), + _ = webmachine_log:log_write(State#state.handle, Msg), + {ok, NewState}; +handle_event({log_info, Msg}, State) -> + NewHandle = maybe_reopen(?MODULE, + State#state.filename, + State#state.handle), + NewState = State#state{handle=NewHandle}, + FormattedMsg = format_req(info, undefined, undefined, Msg), + _ = webmachine_log:log_write(State#state.handle, FormattedMsg), + {ok, NewState}; +handle_event(_Event, State) -> + {ok, State}. + +%% @private +handle_info(_Info, State) -> + {ok, State}. + +%% @private +terminate(_Reason, _State) -> + ok. + +%% @private +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%% =================================================================== +%% Internal functions +%% =================================================================== + + +format_req(Level, Code, Req, Msg) -> + Time = webmachine_log:fmtnow(), + format_req(Level, Time, Code, Req, Msg). + +format_req(info, Time, undefined, _, Msg) -> + [Time, " [info] ", Msg]; +format_req(error, Time, undefined, _, Msg) -> + [Time, " [error] ", Msg]; +format_req(error, Time, 501, Req, _) -> + {Path, _} = Req:path(), + {Method, _} = Req:method(), + Reason = "Webmachine does not support method ", + [Time, " [error] ", Reason, Method, ": path=", Path, $\n]; +format_req(error, Time, 503, Req, _) -> + {Path, _} = Req:path(), + Reason = "Webmachine cannot fulfill the request at this time", + [Time, " [error] ", Reason, ": path=", Path, $\n]; +format_req(error, Time, _Code, Req, Reason) -> + {Path, _} = Req:path(), + Str = io_lib:format("~p", [Reason]), + [Time, " [error] ", "path=", Path, $\x20, Str, $\n]. + +%% @doc Open a new log file for writing +-spec log_open(string()) -> file:io_device(). +log_open(LogName) -> + error_logger:info_msg("opening log file: ~p~n", [LogName]), + ok = filelib:ensure_dir(LogName), + {ok, FD} = file:open(LogName, [read, write, raw]), + {ok, Location} = file:position(FD, eof), + webmachine_log:fix_log(FD, Location), + ok = file:truncate(FD), + FD. + +%% @doc Rotate a log file if the hour it represents +%% has passed. +-spec maybe_reopen(atom(), string(), file:io_device()) -> file:io_device(). +maybe_reopen(Mod, FileName, Handle) -> + Reopen = not filelib:is_regular(FileName), + maybe_reopen(Mod, FileName, Handle, Reopen). + +-spec maybe_reopen(atom(), string(), file:io_device(), boolean()) -> + file:io_device(). +maybe_reopen(_Mod, _FileName, Handle, false) -> + Handle; +maybe_reopen(Mod, FileName, Handle, true) -> + ok = webmachine_log:log_close(Mod, FileName, Handle), + NewHandle = log_open(FileName), + NewHandle. |