| a | b | |
|---|
| 0 | + | diff --git a/src/couchdb/couch_log.erl b/src/couchdb/couch_log.erl |
|---|
| 0 | + | index 2676689..03e2fa7 100644 |
|---|
| 0 | + | --- a/src/couchdb/couch_log.erl |
|---|
| 0 | + | +++ b/src/couchdb/couch_log.erl |
|---|
| 0 | + | @@ -27,10 +27,12 @@ |
|---|
| 0 | + | -define(LEVEL_INFO, 2). |
|---|
| 0 | + | -define(LEVEL_DEBUG, 1). |
|---|
| 0 | + | |
|---|
| 0 | + | +-define(MAX_BUFFER_LEN, 64 * 1024). |
|---|
| 0 | + | + |
|---|
| 0 | + | -record(state, { |
|---|
| 0 | + | - fd, |
|---|
| 0 | + | level, |
|---|
| 0 | + | - sasl |
|---|
| 0 | + | + sasl, |
|---|
| 0 | + | + writer |
|---|
| 0 | + | }). |
|---|
| 0 | + | |
|---|
| 0 | + | debug(Format, Args) -> |
|---|
| 0 | + | @@ -81,17 +83,21 @@ init([]) -> |
|---|
| 0 | + | Sasl = couch_config:get("log", "include_sasl", "true") =:= "true", |
|---|
| 0 | + | |
|---|
| 0 | + | case ets:info(?MODULE) of |
|---|
| 0 | + | - undefined -> ets:new(?MODULE, [named_table]); |
|---|
| 0 | + | + undefined -> ets:new(?MODULE, [named_table, {read_concurrency, true}]); |
|---|
| 0 | + | _ -> ok |
|---|
| 0 | + | end, |
|---|
| 0 | + | ets:insert(?MODULE, {level, Level}), |
|---|
| 0 | + | |
|---|
| 0 | + | - case file:open(Filename, [append]) of |
|---|
| 0 | + | - {ok, Fd} -> |
|---|
| 0 | + | - {ok, #state{fd = Fd, level = Level, sasl = Sasl}}; |
|---|
| 0 | + | - {error, eacces} -> |
|---|
| 0 | + | + process_flag(trap_exit, true), |
|---|
| 0 | + | + Parent = self(), |
|---|
| 0 | + | + Writer = spawn_link(fun() -> writer(Parent, Filename) end), |
|---|
| 0 | + | + |
|---|
| 0 | + | + receive |
|---|
| 0 | + | + {Writer, ok} -> |
|---|
| 0 | + | + {ok, #state{writer = Writer, level = Level, sasl = Sasl}}; |
|---|
| 0 | + | + {Writer, {error, eacces}} -> |
|---|
| 0 | + | {stop, {file_permission_error, Filename}}; |
|---|
| 0 | + | - Error -> |
|---|
| 0 | + | + {Writer, Error} -> |
|---|
| 0 | + | {stop, Error} |
|---|
| 0 | + | end. |
|---|
| 0 | + | |
|---|
| 0 | + | @@ -143,18 +149,21 @@ handle_call({set_level_integer, NewLevel}, State) -> |
|---|
| 0 | + | ets:insert(?MODULE, {level, NewLevel}), |
|---|
| 0 | + | {ok, ok, State#state{level = NewLevel}}. |
|---|
| 0 | + | |
|---|
| 0 | + | +handle_info({'EXIT', Pid, Reason}, #state{writer = Pid}) -> |
|---|
| 0 | + | + io:format("[error] log writer died: ~p~n", [Reason]), |
|---|
| 0 | + | + exit({log_writer_died, Reason}); |
|---|
| 0 | + | handle_info(_Info, State) -> |
|---|
| 0 | + | {ok, State}. |
|---|
| 0 | + | |
|---|
| 0 | + | code_change(_OldVsn, State, _Extra) -> |
|---|
| 0 | + | {ok, State}. |
|---|
| 0 | + | |
|---|
| 0 | + | -terminate(_Arg, #state{fd = Fd}) -> |
|---|
| 0 | + | - file:close(Fd). |
|---|
| 0 | + | +terminate(_Arg, #state{writer = Writer}) -> |
|---|
| 0 | + | + Writer ! stop, |
|---|
| 0 | + | + receive {'EXIT', Writer, _} -> ok end. |
|---|
| 0 | + | |
|---|
| 0 | + | -log(#state{fd = Fd}, ConsoleMsg, FileMsg) -> |
|---|
| 0 | + | - ok = io:put_chars(ConsoleMsg), |
|---|
| 0 | + | - ok = io:put_chars(Fd, FileMsg). |
|---|
| 0 | + | +log(#state{writer = Writer}, ConsoleMsg, FileMsg) -> |
|---|
| 0 | + | + Writer ! {log, FileMsg, ConsoleMsg}. |
|---|
| 0 | + | |
|---|
| 0 | + | get_log_messages(Pid, Level, Format, Args) -> |
|---|
| 0 | + | ConsoleMsg = unicode:characters_to_binary(io_lib:format( |
|---|
| 0 | + | @@ -175,3 +184,41 @@ read(Bytes, Offset) -> |
|---|
| 0 | + | {ok, Chunk} = file:pread(Fd, Start, LogFileSize), |
|---|
| 0 | + | ok = file:close(Fd), |
|---|
| 0 | + | Chunk. |
|---|
| 0 | + | + |
|---|
| 0 | + | + |
|---|
| 0 | + | +writer(Parent, Filename) -> |
|---|
| 0 | + | + case file:open(Filename, [append, raw, binary]) of |
|---|
| 0 | + | + {ok, Fd} -> |
|---|
| 0 | + | + Parent ! {self(), ok}, |
|---|
| 0 | + | + writer_loop(Fd); |
|---|
| 0 | + | + Error -> |
|---|
| 0 | + | + Parent ! {self(), Error} |
|---|
| 0 | + | + end. |
|---|
| 0 | + | + |
|---|
| 0 | + | +writer_loop(Fd) -> |
|---|
| 0 | + | + receive |
|---|
| 0 | + | + {log, FileMsg, ConsoleMsg} -> |
|---|
| 0 | + | + ok = io:put_chars(ConsoleMsg), |
|---|
| 0 | + | + ok = file:write(Fd, FileMsg), |
|---|
| 0 | + | + writer_loop(Fd); |
|---|
| 0 | + | + % writer_loop_batch(Fd, [FileMsg], [ConsoleMsg], byte_size(FileMsg)); |
|---|
| 0 | + | + stop -> |
|---|
| 0 | + | + ok = file:close(Fd) |
|---|
| 0 | + | + end. |
|---|
| 0 | + | + |
|---|
| 0 | + | +writer_loop_batch(Fd, AccFile, AccConsole, Len) when Len >= ?MAX_BUFFER_LEN -> |
|---|
| 0 | + | + ok = io:put_chars(lists:reverse(AccConsole)), |
|---|
| 0 | + | + ok = file:write(Fd, lists:reverse(AccFile)), |
|---|
| 0 | + | + writer_loop(Fd); |
|---|
| 0 | + | + |
|---|
| 0 | + | +writer_loop_batch(Fd, AccFile, AccConsole, Len) -> |
|---|
| 0 | + | + receive |
|---|
| 0 | + | + {log, FileMsg, ConsoleMsg} -> |
|---|
| 0 | + | + writer_loop_batch( |
|---|
| 0 | + | + Fd, [FileMsg | AccFile], [ConsoleMsg | AccConsole], |
|---|
| 0 | + | + Len + byte_size(FileMsg)) |
|---|
| 0 | + | + after 0 -> |
|---|
| 0 | + | + ok = io:put_chars(lists:reverse(AccConsole)), |
|---|
| 0 | + | + ok = file:write(Fd, lists:reverse(AccFile)), |
|---|
| 0 | + | + writer_loop(Fd) |
|---|
| 0 | + | + end. |
|---|
| ... | |
|---|