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:52 UTC

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

Updated Branches:
  refs/heads/1994-merge-rcouch f07bbfcc0 -> 3f5184216


add supports of view changes in the _changes API

Now when the option `seq_indexed=true` is set in the design doc, the
view filter in _changes will use it to retrieve the results. Compared to
the current way, using a view index will be faster to retrieve changes.
It also gives the possibility to filter changes by key or get changes in
a key range. All the view options can be used.

Note 1: if someone is trying to filter a changes with view options when
the views are not indexed by sequence, a 400 error will be returned.
Note 2: The changes will only be returned when the view is updated if
seq_indexed=true


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

Branch: refs/heads/1994-merge-rcouch
Commit: e5856d47067550365e5ae54ef4342c36b7dfbaac
Parents: f07bbfc
Author: benoitc <bc...@gmail.com>
Authored: Fri Feb 7 15:38:34 2014 +0100
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Wed Feb 12 21:23:45 2014 -0600

----------------------------------------------------------------------
 src/couch_util.erl | 7 +++++++
 1 file changed, 7 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e5856d47/src/couch_util.erl
----------------------------------------------------------------------
diff --git a/src/couch_util.erl b/src/couch_util.erl
index 40401e2..2a3bba7 100644
--- a/src/couch_util.erl
+++ b/src/couch_util.erl
@@ -32,6 +32,7 @@
 -export([with_db/2]).
 -export([rfc1123_date/0, rfc1123_date/1]).
 -export([find_in_binary/2]).
+-export([to_atom/1]).
 
 -include("couch_db.hrl").
 
@@ -352,6 +353,12 @@ to_list(V) when is_atom(V) ->
 to_list(V) ->
     lists:flatten(io_lib:format("~p", [V])).
 
+
+to_atom(V) when is_binary(V) ->
+    list_to_atom(binary_to_list(V));
+to_atom(V) when is_list(V) ->
+    list_to_atom(V).
+
 url_encode(Bin) when is_binary(Bin) ->
     url_encode(binary_to_list(Bin));
 url_encode([H|T]) ->


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

Posted by da...@apache.org.
couch_log: be less invasive when using parse_transform

Noticed when running tests vi travis-ci, jiffy doesn't like too much
lager and the build hangs. So instead to compile all modules with the
parse transform, only do it for couch_log. This is the only place where
we really need it anyway.


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

Branch: refs/heads/1994-merge-rcouch
Commit: 10e26f054a3e231a852e2e100a2e0588a98b5b8c
Parents: 95e2f20
Author: benoitc <bc...@gmail.com>
Authored: Wed Feb 12 00:38:27 2014 +0100
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Wed Feb 12 21:24:08 2014 -0600

----------------------------------------------------------------------
 src/couch_log.erl | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/10e26f05/src/couch_log.erl
----------------------------------------------------------------------
diff --git a/src/couch_log.erl b/src/couch_log.erl
index 6cf04f4..82158f6 100644
--- a/src/couch_log.erl
+++ b/src/couch_log.erl
@@ -14,6 +14,8 @@
 
 -behaviour(gen_server).
 
+-compile([{parse_transform, lager_transform}]).
+
 % public API
 -export([start_link/0, stop/0]).
 -export([debug/2, info/2, warn/2, error/2]).


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

Posted by da...@apache.org.
release: version couch.app.src shoud be set manually

fix build issue with some old version of rebar. Now the version of the
couch.app is set manually.

RCOUCH-2 done


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

Branch: refs/heads/1994-merge-rcouch
Commit: ed2f926fc54d02210e4887ccd2f9a36668b8b771
Parents: e5856d4
Author: benoitc <be...@apache.org>
Authored: Sun Feb 9 15:57:44 2014 +0100
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Wed Feb 12 21:23:54 2014 -0600

----------------------------------------------------------------------
 src/couch.app.src        | 41 ++++++++++++++++++++++++++
 src/couch.app.src.script | 67 -------------------------------------------
 src/couch.erl            |  9 ------
 src/couch_server.erl     |  2 +-
 4 files changed, 42 insertions(+), 77 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ed2f926f/src/couch.app.src
----------------------------------------------------------------------
diff --git a/src/couch.app.src b/src/couch.app.src
index e69de29..b3ed46c 100644
--- a/src/couch.app.src
+++ b/src/couch.app.src
@@ -0,0 +1,41 @@
+%% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ft=erlang ts=4 sw=4 et
+
+%% Licensed 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.
+
+
+{application, couch, [
+    {description, "Apache CouchDB"},
+    {vsn, "1.6.1"},
+    {registered, [
+        couch_config,
+        couch_db_update,
+        couch_db_update_notifier_sup,
+        couch_external_manager,
+        couch_index_sup,
+        couch_log,
+        couch_primary_services,
+        couch_query_servers,
+        couch_secondary_services,
+        couch_server,
+        couch_sup,
+        couch_stats_aggregator,
+        couch_stats_collector,
+        couch_task_status
+    ]},
+    {mod, {couch_app, []}},
+    {env, []},
+    {applications, [kernel, stdlib, crypto, sasl, asn1, public_key,
+                    ssl, os_mon, inets]}
+]}.
+

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ed2f926f/src/couch.app.src.script
----------------------------------------------------------------------
diff --git a/src/couch.app.src.script b/src/couch.app.src.script
deleted file mode 100644
index ac8156d..0000000
--- a/src/couch.app.src.script
+++ /dev/null
@@ -1,67 +0,0 @@
-%% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*-
-%% ex: ft=erlang ts=4 sw=4 et
-
-%% Licensed 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.
-
-
-Cfg = case file:consult("../../pkg.vars.config") of
-          {ok, Terms} ->
-              Terms;
-          _Err ->
-              []
-      end,
-
-%% get version infos
-MajorVersion = integer_to_list(proplists:get_value(version_major, Cfg, 0)),
-MinorVersion = integer_to_list(proplists:get_value(version_minor, Cfg, 0)),
-RevVersion = integer_to_list(proplists:get_value(version_revision, Cfg, 0)),
-StageVersion = proplists:get_value(version_stage, Cfg, ""),
-RelVersion = proplists:get_value(version_release, Cfg, ""),
-
-%% build the version
-BaseVersion = MajorVersion ++ "." ++ MinorVersion ++ "." ++ RevVersion,
-SecondaryVersion = StageVersion ++ RelVersion,
-RelVsn = case os:getenv("RELEASE") of
-    "1" ->
-        BaseVersion;
-    _ ->
-        BaseVersion ++ SecondaryVersion
-end,
-
-
-[
-    {application, couch, [
-        {description, "Apache CouchDB"},
-        {vsn, "1.6.1"},
-        {registered, [
-            couch_config,
-            couch_db_update,
-            couch_db_update_notifier_sup,
-            couch_external_manager,
-            couch_index_sup,
-            couch_log,
-            couch_primary_services,
-            couch_query_servers,
-            couch_secondary_services,
-            couch_server,
-            couch_sup,
-            couch_stats_aggregator,
-            couch_stats_collector,
-            couch_task_status
-        ]},
-        {mod, {couch_app, []}},
-        {env, [{couch_rel, RelVsn}]},
-        {applications, [kernel, stdlib, crypto, sasl, asn1, public_key,
-                        ssl, os_mon, inets]}
-    ]}
-].

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ed2f926f/src/couch.erl
----------------------------------------------------------------------
diff --git a/src/couch.erl b/src/couch.erl
index fe4f1a8..59fe7bc 100644
--- a/src/couch.erl
+++ b/src/couch.erl
@@ -14,7 +14,6 @@
 
 -export([get_app_env/2,
          version/0,
-         release_version/0,
          start/0,
          stop/0,
          restart/0,
@@ -34,14 +33,6 @@ version() ->
             "0.0.0"
     end.
 
-release_version() ->
-    case application:get_env(couch, couch_rel) of
-        {ok, Vsn} ->
-            Vsn;
-        _ ->
-            "0.0.0"
-    end.
-
 start() ->
     couch_util:start_app_deps(couch),
     application:start(couch).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ed2f926f/src/couch_server.erl
----------------------------------------------------------------------
diff --git a/src/couch_server.erl b/src/couch_server.erl
index 91b4bc7..d80aa1d 100644
--- a/src/couch_server.erl
+++ b/src/couch_server.erl
@@ -35,7 +35,7 @@ dev_start() ->
     couch:start().
 
 get_version() ->
-    couch:release_version().
+    couch:version().
 get_version(short) ->
   %% strip git hash from version string
   [Version|_Rest] = string:tokens(get_version(), "+"),


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

Posted by da...@apache.org.
couch_log: make sure that the the log file can be set in the ini

For some reason noone noticed until now, but changing the log file was
only possible in the app.config until now. This change fix this by doing
the following:

- when couch_log starts it check if the log file handler has already
  been started using the app.config. If not it start a new handler
- when the filename change after a config update using the API, the old
  file handler is shutdown and a new one is started with the new config.


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

Branch: refs/heads/1994-merge-rcouch
Commit: 3f5184216066fc71451607426b52e973a4b04f03
Parents: 10e26f0
Author: benoitc <bc...@gmail.com>
Authored: Wed Feb 12 01:56:39 2014 +0100
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Wed Feb 12 21:24:14 2014 -0600

----------------------------------------------------------------------
 src/couch_log.erl | 77 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 75 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/3f518421/src/couch_log.erl
----------------------------------------------------------------------
diff --git a/src/couch_log.erl b/src/couch_log.erl
index 82158f6..787f25a 100644
--- a/src/couch_log.erl
+++ b/src/couch_log.erl
@@ -144,6 +144,9 @@ init([]) ->
     Sasl = couch_config:get("log", "include_sasl", "true") =:= "true",
     LevelByModule = couch_config:get("log_level_by_module"),
 
+    %% maybe start the log file backend
+    maybe_start_logfile_backend(Filename, ALevel),
+
     %% initialise the ets table if needed
     case ets:info(?MODULE) of
         undefined -> ets:new(?MODULE, [named_table]);
@@ -172,7 +175,7 @@ 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) ->
+handle_cast(config_update, #state{log_file=OldFilename}=State) ->
     Filename = log_file(),
     ALevel = list_to_atom(couch_config:get("log", "level", "info")),
     Level = level_integer(ALevel),
@@ -180,6 +183,12 @@ handle_cast(config_update, State) ->
     %% set default module
     ets:insert(?MODULE, {level, Level}),
 
+    %% should we restart the file backend with a new config?
+    if OldFilename =/= Filename ->
+            restart_logfile_backend(OldFilename, Filename, ALevel);
+        true -> ok
+    end,
+
     %% set log level
     set_loglevel(Filename, ALevel),
 
@@ -246,6 +255,50 @@ read(Bytes, Offset) ->
     ok = file:close(Fd),
     Chunk.
 
+
+maybe_start_logfile_backend(Filename, Level) ->
+    Started = case application:get_env(lager, handlers) of
+        undefined -> false;
+        {ok, Handlers} ->
+            LogFiles = lists:foldl(fun
+                    ({lager_file_backend, Config}, Acc) ->
+                        [hfile(Config) | Acc];
+                    (_, Acc) ->
+                        Acc
+                end, [], Handlers),
+            lists:member(Filename, LogFiles)
+    end,
+
+    case Started of
+        true -> ok;
+        false ->
+            Config = [{file, Filename},
+                      {level, Level},
+                      {formatter, lager_default_formatter},
+                      {formatter_config,
+                       ["[", time, "] [", pid, "] [", severity, "] ",
+                        message, "\n"]}],
+            HandlerId = {lager_file_backend, Filename},
+            {ok, _} = supervisor:start_child(lager_handler_watcher_sup,
+                                             [lager_event, HandlerId, Config])
+    end.
+
+
+restart_logfile_backend(OldFilename, Filename, Level) ->
+    ok = gen_event:delete_handler(lager_event, {lager_file_backend,
+                                                OldFilename}, []),
+
+    %% restart a new handler
+    Config = [{file, Filename},
+              {level, Level},
+              {formatter, lager_default_formatter},
+              {formatter_config,
+               ["[", time, "] [", pid, "] [", severity, "] ", message, "\n"]}],
+    HandlerId = {lager_file_backend, Filename},
+    {ok, _} = supervisor:start_child(lager_handler_watcher_sup,
+                                     [lager_event, HandlerId, Config]),
+    ok.
+
 set_loglevel(Filename, ALevel) ->
     %% set default log level
     lager:set_loglevel(lager_console_backend, ALevel),
@@ -260,10 +313,30 @@ set_loglevel(Filename, 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).
+
+hfile({FileName, LogLevel}) when is_list(FileName), is_atom(LogLevel) ->
+    %% backwards compatability hack
+    FileName;
+hfile({FileName, LogLevel, _Size, _Date, _Count})
+        when is_list(FileName), is_atom(LogLevel) ->
+    %% backwards compatability hack
+    FileName;
+hfile([{FileName, LogLevel, _Size, _Date, _Count}, {Formatter, _FormatterConfig}])
+    when is_list(FileName), is_atom(LogLevel), is_atom(Formatter) ->
+    %% backwards compatability hack
+    FileName;
+hfile([LogFile,{Formatter}]) ->
+    %% backwards compatability hack
+    hfile([LogFile,{Formatter,[]}]);
+hfile([{FileName, LogLevel}, {Formatter, _FormatterConfig}])
+    when is_list(FileName), is_atom(LogLevel), is_atom(Formatter) ->
+    %% backwards compatability hack
+   FileName;
+hfile(LogFileConfig) when is_list(LogFileConfig) ->
+    proplists:get_value(file, LogFileConfig).


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

Posted by da...@apache.org.
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).