aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2017-02-16 08:07:41 +0100
committerGuido Günther <agx@sigxcpu.org>2017-02-16 08:07:41 +0100
commit4b9ed81166b40e3c2690f7505348bfc889eaf272 (patch)
treef9b4217a17e9d4df99cf4860fc1f12cccda68953
parenteefbd57f8be7cd5263c1e4f4a16976beafc9dcba (diff)
Add our own error log handler
This handler is logrotate friendly as it does not add any datetime into the filename and the log file is recreated if moved.
-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.