aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ldapsp_app.erl2
-rw-r--r--src/ldapsp_error_log_handler.erl160
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.