You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2014/02/13 04:25:54 UTC

[3/5] couch commit: updated refs/heads/1994-merge-rcouch to 3f51842

couch_log: use lager

With this change instead to use our own way to log file we are using
lager which improve the logging which will make couchdb more tolerant in
the face of large or many log messages, won't out of memory the node.

Note: Lager can handle multiple backend butwe are for now only handling
the file and console backend in the ini file. Other backends can be
configured using the app.config file.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/95e2f202
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/95e2f202
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/95e2f202

Branch: refs/heads/1994-merge-rcouch
Commit: 95e2f2026f3d1ce3296ff2d6aaaf759530a0580b
Parents: ed2f926
Author: benoitc <bc...@gmail.com>
Authored: Wed Feb 12 00:01:46 2014 +0100
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Wed Feb 12 21:24:01 2014 -0600

----------------------------------------------------------------------
 src/couch.app.src |   2 +-
 src/couch_log.erl | 209 ++++++++++++++++++++++++++-----------------------
 2 files changed, 112 insertions(+), 99 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/95e2f202/src/couch.app.src
----------------------------------------------------------------------
diff --git a/src/couch.app.src b/src/couch.app.src
index b3ed46c..8674784 100644
--- a/src/couch.app.src
+++ b/src/couch.app.src
@@ -35,7 +35,7 @@
     ]},
     {mod, {couch_app, []}},
     {env, []},
-    {applications, [kernel, stdlib, crypto, sasl, asn1, public_key,
+    {applications, [kernel, stdlib, lager, crypto, sasl, asn1, public_key,
                     ssl, os_mon, inets]}
 ]}.
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/95e2f202/src/couch_log.erl
----------------------------------------------------------------------
diff --git a/src/couch_log.erl b/src/couch_log.erl
index 7cfd47b..6cf04f4 100644
--- a/src/couch_log.erl
+++ b/src/couch_log.erl
@@ -11,7 +11,8 @@
 % the License.
 
 -module(couch_log).
--behaviour(gen_event).
+
+-behaviour(gen_server).
 
 % public API
 -export([start_link/0, stop/0]).
@@ -20,9 +21,10 @@
 -export([debug_on/1, info_on/1, warn_on/1, get_level/1, get_level_integer/1, set_level/2]).
 -export([read/2]).
 
-% gen_event callbacks
--export([init/1, handle_event/2, terminate/2, code_change/3]).
--export([handle_info/2, handle_call/2]).
+% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+         terminate/2, code_change/3]).
+
 
 -define(LEVEL_ERROR, 4).
 -define(LEVEL_WARN, 3).
@@ -30,26 +32,22 @@
 -define(LEVEL_DEBUG, 1).
 
 -record(state, {
-    fd,
+    log_file,
     level,
     sasl
 }).
 
 debug(Format, Args) ->
-    {ConsoleMsg, FileMsg} = get_log_messages(self(), debug, Format, Args),
-    gen_event:sync_notify(error_logger, {couch_debug, ConsoleMsg, FileMsg}).
+    lager:debug(Format, Args).
 
 info(Format, Args) ->
-    {ConsoleMsg, FileMsg} = get_log_messages(self(), info, Format, Args),
-    gen_event:sync_notify(error_logger, {couch_info, ConsoleMsg, FileMsg}).
+    lager:info(Format, Args).
 
 warn(Format, Args) ->
-    {ConsoleMsg, FileMsg} = get_log_messages(self(), warn, Format, Args),
-    gen_event:sync_notify(error_logger, {couch_warn, ConsoleMsg, FileMsg}).
+    lager:warning(Format, Args).
 
 error(Format, Args) ->
-    {ConsoleMsg, FileMsg} = get_log_messages(self(), error, Format, Args),
-    gen_event:sync_notify(error_logger, {couch_error, ConsoleMsg, FileMsg}).
+    lager:error(Format, Args).
 
 
 level_integer(error)    -> ?LEVEL_ERROR;
@@ -63,54 +61,6 @@ level_atom(?LEVEL_WARN) -> warn;
 level_atom(?LEVEL_INFO) -> info;
 level_atom(?LEVEL_DEBUG) -> debug.
 
-
-start_link() ->
-    couch_event_sup:start_link({local, couch_log}, error_logger, couch_log, []).
-
-stop() ->
-    couch_event_sup:stop(couch_log).
-
-init([]) ->
-    % read config and register for configuration changes
-
-    % just stop if one of the config settings change. couch_sup
-    % will restart us and then we will pick up the new settings.
-    ok = couch_config:register(
-        fun("log", "file") ->
-            ?MODULE:stop();
-        ("log", "level") ->
-            ?MODULE:stop();
-        ("log", "include_sasl") ->
-            ?MODULE:stop();
-        ("log_level_by_module", _) ->
-            ?MODULE:stop()
-        end),
-
-    Filename = couch_config:get("log", "file", "couchdb.log"),
-    Level = level_integer(list_to_atom(couch_config:get("log", "level", "info"))),
-    Sasl = couch_config:get("log", "include_sasl", "true") =:= "true",
-    LevelByModule = couch_config:get("log_level_by_module"),
-
-    case ets:info(?MODULE) of
-    undefined -> ets:new(?MODULE, [named_table]);
-    _ -> ok
-    end,
-    ets:insert(?MODULE, {level, Level}),
-    lists:foreach(fun({Module, ModuleLevel}) ->
-        ModuleLevelInteger = level_integer(list_to_atom(ModuleLevel)),
-        ets:insert(?MODULE, {Module, ModuleLevelInteger})
-    end, LevelByModule),
-
-
-    case file:open(Filename, [append]) of
-    {ok, Fd} ->
-        {ok, #state{fd = Fd, level = Level, sasl = Sasl}};
-    {error, Reason} ->
-        ReasonStr = file:format_error(Reason),
-        io:format("Error opening log file ~s: ~s", [Filename, ReasonStr]),
-        {stop, {error, ReasonStr, Filename}}
-    end.
-
 debug_on() ->
     get_level_integer() =< ?LEVEL_DEBUG.
 
@@ -163,55 +113,96 @@ set_level_integer(Int) ->
 set_level_integer(Module, Int) ->
     gen_event:call(error_logger, couch_log, {set_level_integer, Module, Int}).
 
-handle_event({couch_error, ConMsg, FileMsg}, State) ->
-    log(State, ConMsg, FileMsg),
-    {ok, State};
-handle_event({couch_warn, ConMsg, FileMsg}, State) ->
-    log(State, ConMsg, FileMsg),
-    {ok, State};
-handle_event({couch_info, ConMsg, FileMsg}, State) ->
-    log(State, ConMsg, FileMsg),
-    {ok, State};
-handle_event({couch_debug, ConMsg, FileMsg}, State) ->
-    log(State, ConMsg, FileMsg),
-    {ok, State};
-handle_event({error_report, _, {Pid, _, _}}=Event, #state{sasl = true} = St) ->
-    {ConMsg, FileMsg} = get_log_messages(Pid, error, "~p", [Event]),
-    log(St, ConMsg, FileMsg),
-    {ok, St};
-handle_event({error, _, {Pid, Format, Args}}, #state{sasl = true} = State) ->
-    {ConMsg, FileMsg} = get_log_messages(Pid, error, Format, Args),
-    log(State, ConMsg, FileMsg),
-    {ok, State};
-handle_event(_Event, State) ->
-    {ok, State}.
 
-handle_call({set_level_integer, NewLevel}, State) ->
+
+start_link() ->
+    gen_server:start_link({local, couch_log}, couch_log, [], []).
+
+stop() ->
+    couch_event_sup:stop(couch_log).
+
+init([]) ->
+    % read config and register for configuration changes
+    ok = couch_config:register(fun
+                ("log", "file") ->
+                    gen_server:cast(?MODULE, config_update);
+                ("log", "level") ->
+                    gen_server:cast(?MODULE, config_update);
+                ("log", "include_sasl") ->
+                    gen_server:cast(?MODULE, {config_update, include_sasl});
+                ("log_level_by_module", _) ->
+                    gen_server:cast(?MODULE,
+                                    {config_update, log_level_by_module})
+            end),
+
+
+    Filename = log_file(),
+    ALevel = list_to_atom(couch_config:get("log", "level", "info")),
+    Level = level_integer(ALevel),
+    Sasl = couch_config:get("log", "include_sasl", "true") =:= "true",
+    LevelByModule = couch_config:get("log_level_by_module"),
+
+    %% initialise the ets table if needed
+    case ets:info(?MODULE) of
+        undefined -> ets:new(?MODULE, [named_table]);
+        _ -> ok
+    end,
+
+    %% set the default level
+    ets:insert(?MODULE, {level, Level}),
+
+    %% initialise the log level by modules
+    lists:foreach(fun({Module, ModuleLevel}) ->
+        ModuleLevelInteger = level_integer(list_to_atom(ModuleLevel)),
+        ets:insert(?MODULE, {Module, ModuleLevelInteger})
+    end, LevelByModule),
+
+    %% set default log level
+    set_loglevel(Filename, ALevel),
+
+    {ok, #state{log_file=Filename, level = Level, sasl = Sasl}}.
+
+handle_call({set_level_integer, NewLevel}, _From, State) ->
     ets:insert(?MODULE, {level, NewLevel}),
     {ok, ok, State#state{level = NewLevel}};
 
-handle_call({set_level_integer, Module, NewLevel}, State) ->
+handle_call({set_level_integer, Module, NewLevel}, _From, State) ->
     ets:insert(?MODULE, {Module, NewLevel}),
     {ok, ok, State#state{level = NewLevel}}.
 
+handle_cast(config_update, State) ->
+    Filename = log_file(),
+    ALevel = list_to_atom(couch_config:get("log", "level", "info")),
+    Level = level_integer(ALevel),
+
+    %% set default module
+    ets:insert(?MODULE, {level, Level}),
+
+    %% set log level
+    set_loglevel(Filename, ALevel),
+
+    {noreply, State#state{log_file=Filename, level = Level}};
+
+handle_cast({config_update, include_sasl}, State) ->
+    Sasl = couch_config:get("log", "include_sasl", "true") =:= "true",
+    {noreply, State#state{sasl=Sasl}};
+handle_cast({config_update, log_level_by_module}, State) ->
+    LevelByModule = couch_config:get("log_level_by_module"),
+    lists:foreach(fun({Module, ModuleLevel}) ->
+        ModuleLevelInteger = level_integer(list_to_atom(ModuleLevel)),
+        ets:insert(?MODULE, {Module, ModuleLevelInteger})
+    end, LevelByModule),
+
+    {noreply, State}.
+
 handle_info(_Info, State) ->
     {ok, State}.
 
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
 
-terminate(_Arg, #state{fd = Fd}) ->
-    file:close(Fd).
-
-log(#state{fd = Fd}, ConsoleMsg, FileMsg) ->
-    ok = io:put_chars(ConsoleMsg),
-    ok = io:put_chars(Fd, FileMsg).
-
-get_log_messages(Pid, Level, Format, Args) ->
-    ConsoleMsg = unicode:characters_to_binary(io_lib:format(
-        "[~s] [~p] " ++ Format ++ "~n", [Level, Pid | Args])),
-    FileMsg = ["[", couch_util:rfc1123_date(), "] ", ConsoleMsg],
-    {ConsoleMsg, iolist_to_binary(FileMsg)}.
+terminate(_Arg, _State) ->
+    ok.
 
 
 % Read Bytes bytes from the end of log file, jumping Offset bytes towards
@@ -231,7 +222,7 @@ get_log_messages(Pid, Level, Format, Args) ->
 % |__________| 100
 
 read(Bytes, Offset) ->
-    LogFileName = couch_config:get("log", "file"),
+    LogFileName = log_file(),
     LogFileSize = filelib:file_size(LogFileName),
     MaxChunkSize = list_to_integer(
         couch_config:get("httpd", "log_max_chunk_size", "1000000")),
@@ -252,3 +243,25 @@ read(Bytes, Offset) ->
     {ok, Chunk} = file:pread(Fd, Start, Bytes),
     ok = file:close(Fd),
     Chunk.
+
+set_loglevel(Filename, ALevel) ->
+    %% set default log level
+    lager:set_loglevel(lager_console_backend, ALevel),
+    lager:set_loglevel(lager_file_backend, Filename, ALevel),
+
+    %% set the log level for other handlers
+    case application:get_env(lager, handlers) of
+        undefined -> ok;
+        {ok, Handlers} ->
+            lists:foreach(fun(Handler) ->
+                        lager:set_loglevel(Handler, ALevel)
+                end, Handlers)
+    end.
+
+
+log_file() ->
+    DefaultLogFile = case application:get_env(couch, log_file) of
+        undefined -> "couchdb.log";
+        FName -> FName
+    end,
+    couch_config:get("log", "file", DefaultLogFile).