You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ko...@apache.org on 2021/04/22 20:46:06 UTC

[couchdb] branch new-logger created (now 0a6200d)

This is an automated email from the ASF dual-hosted git repository.

kocolosk pushed a change to branch new-logger
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


      at 0a6200d  Add a temporary logger config

This branch includes the following new commits:

     new b41ffa2  Drop support for Erlang < 21
     new 898050d  Produce structured logging reports
     new 0a6200d  Add a temporary logger config

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[couchdb] 02/03: Produce structured logging reports

Posted by ko...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kocolosk pushed a commit to branch new-logger
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 898050d63f2c2e92b8827adf717c1867344d85a5
Author: Adam Kocoloski <ko...@apache.org>
AuthorDate: Thu Apr 22 15:13:51 2021 -0400

    Produce structured logging reports
---
 src/aegis/src/aegis_server.erl                     |   3 +
 src/chttpd/include/chttpd.hrl                      |   1 +
 src/chttpd/src/chttpd.erl                          |  56 +++++++-
 src/chttpd/src/chttpd_auth_cache.erl               |  23 ++++
 src/chttpd/src/chttpd_cors.erl                     |   7 +
 src/chttpd/src/chttpd_db.erl                       |  17 +++
 src/chttpd/src/chttpd_handlers.erl                 |   7 +
 src/chttpd/src/chttpd_stats.erl                    |   9 +-
 src/chttpd/src/chttpd_sup.erl                      |  10 ++
 src/couch/src/couch_drv.erl                        |   2 +
 src/couch/src/couch_flags_config.erl               |  80 +++++------
 src/couch/src/couch_httpd_auth.erl                 |  25 ++++
 src/couch/src/couch_httpd_multipart.erl            |  11 ++
 src/couch/src/couch_httpd_vhost.erl                |   6 +
 src/couch/src/couch_proc_manager.erl               |   1 +
 src/couch/src/couch_sup.erl                        |  34 ++++-
 .../src/couch_expiring_cache_fdb.erl               |   2 +
 .../src/couch_expiring_cache_server.erl            |   5 +
 src/couch_jobs/src/couch_jobs_activity_monitor.erl |  11 ++
 src/couch_jobs/src/couch_jobs_notifier.erl         |   5 +
 src/couch_jobs/src/couch_jobs_server.erl           |  11 ++
 src/couch_js/src/couch_js_native_process.erl       |  40 +++++-
 src/couch_js/src/couch_js_os_process.erl           |  64 +++++++++
 src/couch_js/src/couch_js_proc_manager.erl         |   8 ++
 src/couch_js/src/couch_js_query_servers.erl        |   7 +
 src/couch_replicator/src/couch_replicator.erl      |   9 ++
 .../src/couch_replicator_api_wrap.erl              |  21 +++
 .../src/couch_replicator_auth_session.erl          |  13 ++
 .../src/couch_replicator_changes_reader.erl        |  23 ++++
 .../src/couch_replicator_connection.erl            |   8 ++
 src/couch_replicator/src/couch_replicator_docs.erl |  25 +++-
 .../src/couch_replicator_httpc.erl                 |  29 ++++
 src/couch_replicator/src/couch_replicator_job.erl  | 151 ++++++++++++++++++++-
 .../src/couch_replicator_job_server.erl            |  33 +++++
 .../src/couch_replicator_parse.erl                 |  27 ++++
 .../src/couch_replicator_worker.erl                |  94 ++++++++++++-
 src/couch_views/src/couch_views_indexer.erl        |  17 +++
 src/couch_views/src/couch_views_server.erl         |   5 +
 src/couch_views/src/couch_views_sup.erl            |   2 +
 src/couch_views/src/couch_views_updater.erl        |  15 ++
 src/couch_views/src/couch_views_util.erl           |   7 +
 src/ctrace/src/ctrace.erl                          |   1 +
 src/ctrace/src/ctrace_config.erl                   |   3 +
 src/ctrace/test/ctrace_config_test.erl             |   3 +
 src/fabric/src/fabric2_db.erl                      |   2 +
 src/fabric/src/fabric2_db_expiration.erl           |  15 +-
 src/fabric/src/fabric2_index.erl                   |  15 ++
 src/fabric/src/fabric2_server.erl                  |  35 +++++
 src/fabric/src/fabric2_users_db.erl                |   8 ++
 src/mango/src/mango_cursor_view.erl                |   2 +
 src/mango/src/mango_idx_view.erl                   |   7 +
 51 files changed, 959 insertions(+), 56 deletions(-)

diff --git a/src/aegis/src/aegis_server.erl b/src/aegis/src/aegis_server.erl
index 15fea4c..92ba7e8 100644
--- a/src/aegis/src/aegis_server.erl
+++ b/src/aegis/src/aegis_server.erl
@@ -18,6 +18,7 @@
 
 
 -include("aegis.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 %% aegis_server API
@@ -94,6 +95,7 @@ encrypt(#{} = Db, Key, Value) when is_binary(Key), is_binary(Value) ->
                 CipherText when is_binary(CipherText) ->
                     CipherText;
                 {error, {_Tag, {_C_FileName,_LineNumber}, _Desc} = Reason} ->
+                    ?LOG_ERROR(#{what => encrypt_failure, details => Reason}),
                     couch_log:error("aegis encryption failure: ~p ", [Reason]),
                     erlang:error(decryption_failed);
                 {error, Reason} ->
@@ -119,6 +121,7 @@ decrypt(#{} = Db, Key, Value) when is_binary(Key), is_binary(Value) ->
                 PlainText when is_binary(PlainText) ->
                     PlainText;
                 {error, {_Tag, {_C_FileName,_LineNumber}, _Desc} = Reason} ->
+                    ?LOG_ERROR(#{what => decrypt_failure, details => Reason}),
                     couch_log:error("aegis decryption failure: ~p ", [Reason]),
                     erlang:error(decryption_failed);
                 {error, Reason} ->
diff --git a/src/chttpd/include/chttpd.hrl b/src/chttpd/include/chttpd.hrl
index a7f9aaa..42263d9 100644
--- a/src/chttpd/include/chttpd.hrl
+++ b/src/chttpd/include/chttpd.hrl
@@ -10,6 +10,7 @@
 % License for the specific language governing permissions and limitations under
 % the License.
 
+-include_lib("kernel/include/logger.hrl").
 
 -record(httpd_resp, {
     end_ts,
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index 6741ca3..5d10d7d 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -16,6 +16,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("chttpd/include/chttpd.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -export([start_link/0, start_link/1, start_link/2,
     stop/0, handle_request/1, handle_request_int/1,
@@ -206,7 +207,13 @@ handle_request_int(MochiReq) ->
     true ->
         couch_log:notice("MethodOverride: ~s (real method was ~s)", [MethodOverride, Method1]),
         case Method1 of
-        'POST' -> couch_util:to_existing_atom(MethodOverride);
+        'POST' ->
+            ?LOG_NOTICE(#{
+                what => http_method_override,
+                result => ok,
+                new_method => MethodOverride
+            }),
+            couch_util:to_existing_atom(MethodOverride);
         _ ->
             % Ignore X-HTTP-Method-Override when the original verb isn't POST.
             % I'd like to send a 406 error to the client, but that'd require a nasty refactor.
@@ -268,6 +275,11 @@ handle_request_int(MochiReq) ->
             span_ok(HttpResp),
             {ok, Resp};
         #httpd_resp{status = aborted, reason = Reason} ->
+            ?LOG_ERROR(#{
+                what => abnormal_response_termation,
+                id => get(nonce),
+                details => Reason
+            }),
             couch_log:error("Response abnormally terminated: ~p", [Reason]),
             exit(normal)
     end.
@@ -348,6 +360,14 @@ catch_error(HttpReq, exit, {mochiweb_recv_error, E}, _Stack) ->
         peer = Peer,
         original_method = Method
     } = HttpReq,
+    ?LOG_NOTICE(#{
+        what => mochiweb_recv_error,
+        id => get(nonce),
+        peer => Peer,
+        method => Method,
+        path => MochiReq:get(raw_path),
+        details => E
+    }),
     couch_log:notice("mochiweb_recv_error for ~s - ~p ~s - ~p", [
         Peer,
         Method,
@@ -413,9 +433,24 @@ maybe_log(#httpd{} = HttpReq, #httpd_resp{should_log = true} = HttpResp) ->
     User = get_user(HttpReq),
     Host = MochiReq:get_header_value("Host"),
     RawUri = MochiReq:get(raw_path),
-    RequestTime = timer:now_diff(EndTime, BeginTime) / 1000,
+    RequestTime = round(timer:now_diff(EndTime, BeginTime) / 1000),
+    % Wish List
+    % - client port
+    % - timers: connection, request, time to first byte, ...
+    % - response size
+    % 
+    ?LOG_NOTICE(#{
+        method => Method,
+        path => RawUri,
+        code => Code,
+        id => get(nonce),
+        user => User,
+        % req_size => MochiReq:get(body_length),
+        src => #{ip4 => Peer},
+        duration => RequestTime
+    }, #{domain => [chttpd_access_log]}),
     couch_log:notice("~s ~s ~s ~s ~s ~B ~p ~B", [Host, Peer, User,
-        Method, RawUri, Code, Status, round(RequestTime)]);
+        Method, RawUri, Code, Status, RequestTime]);
 maybe_log(_HttpReq, #httpd_resp{should_log = false}) ->
     ok.
 
@@ -1246,6 +1281,14 @@ maybe_decompress(Httpd, Body) ->
 log_error_with_stack_trace({bad_request, _, _}) ->
     ok;
 log_error_with_stack_trace({Error, Reason, Stack}) ->
+    ?LOG_ERROR(#{
+        what => request_failure,
+        id => get(nonce),
+        error => Error,
+        reason => Reason,
+        hash => stack_hash(Stack),
+        stacktrace => Stack
+    }),
     EFmt = if is_binary(Error) -> "~s"; true -> "~w" end,
     RFmt = if is_binary(Reason) -> "~s"; true -> "~w" end,
     Fmt = "req_err(~w) " ++ EFmt ++ " : " ++ RFmt ++ "~n    ~p",
@@ -1396,8 +1439,13 @@ get_action(#httpd{} = Req) ->
     try
         chttpd_handlers:handler_info(Req)
     catch Tag:Error ->
+        ?LOG_ERROR(#{
+            what => tracing_configuration_failure,
+            tag => Tag,
+            details => Error
+        }),
         couch_log:error("Cannot set tracing action ~p:~p", [Tag, Error]),
-        {undefind, #{}}
+        {undefined, #{}}
     end.
 
 span_ok(#httpd_resp{code = Code}) ->
diff --git a/src/chttpd/src/chttpd_auth_cache.erl b/src/chttpd/src/chttpd_auth_cache.erl
index c5a56bd..88ffb7a 100644
--- a/src/chttpd/src/chttpd_auth_cache.erl
+++ b/src/chttpd/src/chttpd_auth_cache.erl
@@ -22,6 +22,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch/include/couch_js_functions.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(CACHE, chttpd_auth_cache_lru).
 -define(RELISTEN_DELAY, 5000).
@@ -74,6 +75,7 @@ get_from_cache(UserName) ->
     try ets_lru:lookup_d(?CACHE, UserName) of
         {ok, Props} ->
             couch_stats:increment_counter([couchdb, auth_cache_hits]),
+            ?LOG_DEBUG(#{what => cache_hit, user => UserName}),
             couch_log:debug("cache hit for ~s", [UserName]),
             Props;
         _ ->
@@ -96,6 +98,7 @@ maybe_increment_auth_cache_miss(UserName) ->
     case lists:keymember(?b2l(UserName), 1, Admins) of
         false ->
             couch_stats:increment_counter([couchdb, auth_cache_misses]),
+            ?LOG_DEBUG(#{what => cache_miss, user => UserName}),
             couch_log:debug("cache miss for ~s", [UserName]);
         _True ->
             ok
@@ -137,9 +140,18 @@ handle_info({'DOWN', _, _, Pid, Reason}, #state{changes_pid=Pid} = State) ->
         {seq, EndSeq} ->
             EndSeq;
     {database_does_not_exist, _} ->
+            ?LOG_NOTICE(#{
+                what => changes_listener_died,
+                reason => database_does_not_exist,
+                details => "create the _users database to silence this notice"
+            }),
             couch_log:notice("~p changes listener died because the _users database does not exist. Create the database to silence this notice.", [?MODULE]),
             0;
         _ ->
+            ?LOG_NOTICE(#{
+                what => changes_listener_died,
+                reason => Reason
+            }),
             couch_log:notice("~p changes listener died ~r", [?MODULE, Reason]),
             0
     end,
@@ -192,6 +204,7 @@ changes_callback({change, {Change}}, _) ->
             ok;
         DocId ->
             UserName = username(DocId),
+            ?LOG_DEBUG(#{what => invalidate_cache, user => UserName}),
             couch_log:debug("Invalidating cached credentials for ~s", [UserName]),
             ets_lru:remove(?CACHE, UserName)
     end,
@@ -221,6 +234,10 @@ load_user_from_db(UserName) ->
         {Props} = couch_doc:to_json_obj(Doc, []),
         Props;
     _Else ->
+        ?LOG_DEBUG(#{
+            what => missing_user_document,
+            user => UserName
+        }),
         couch_log:debug("no record of user ~s", [UserName]),
         nil
     catch error:database_does_not_exist ->
@@ -267,6 +284,12 @@ ensure_auth_ddoc_exists(Db, DDocId) ->
                 update_doc_ignoring_conflict(Db, NewDoc)
         end;
     {error, Reason} ->
+        ?LOG_NOTICE(#{
+            what => ensure_auth_ddoc_exists_failure,
+            db => dbname(),
+            docid => DDocId,
+            details => Reason
+        }),
         couch_log:notice("Failed to ensure auth ddoc ~s/~s exists for reason: ~p", [dbname(), DDocId, Reason]),
         ok
     end,
diff --git a/src/chttpd/src/chttpd_cors.erl b/src/chttpd/src/chttpd_cors.erl
index a8dd348..ba13233 100644
--- a/src/chttpd/src/chttpd_cors.erl
+++ b/src/chttpd/src/chttpd_cors.erl
@@ -27,6 +27,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("chttpd/include/chttpd_cors.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 %% http://www.w3.org/TR/cors/#resource-preflight-requests
@@ -51,6 +52,12 @@ maybe_handle_preflight_request(#httpd{}=Req, Config) ->
                 not_preflight ->
                     not_preflight;
                 UnknownError ->
+                    ?LOG_ERROR(#{
+                        what => preflight_request_error,
+                        origin => get_origin(Req),
+                        accepted_origins => get_accepted_origins(Req, Config),
+                        details => UnknownError
+                    }),
                     couch_log:error(
                         "Unknown response of chttpd_cors:preflight_request(~p): ~p",
                         [Req, UnknownError]
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 8f08c7f..4a7b631 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -16,6 +16,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_views/include/couch_views.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -export([handle_request/1, handle_compact_req/2, handle_design_req/2,
     db_req/2, couch_doc_open/4,handle_changes_req/2,
@@ -360,6 +361,12 @@ db_req(#httpd{method='POST', path_parts=[DbName]}=Req, Db) ->
                     chttpd_stats:incr_writes(),
                     ok;
                 Error ->
+                    ?LOG_DEBUG(#{
+                        what => async_update_error,
+                        db => DbName,
+                        docid => DocId,
+                        details => Error
+                    }),
                     couch_log:debug("Batch doc error (~s): ~p",[DocId, Error])
                 end
             end),
@@ -1108,6 +1115,12 @@ db_doc_req(#httpd{method='PUT'}=Req, Db, DocId) ->
                         chttpd_stats:incr_writes(),
                         ok;
                     Error ->
+                        ?LOG_NOTICE(#{
+                            what => async_update_error,
+                            db => DbName,
+                            docid => DocId,
+                            details => Error
+                        }),
                         couch_log:notice("Batch doc error (~s): ~p",[DocId, Error])
                     end
                 end),
@@ -1944,6 +1957,10 @@ monitor_attachments(Atts) when is_list(Atts) ->
             stub ->
                 Monitors;
             Else ->
+                ?LOG_ERROR(#{
+                    what => malformed_attachment_data,
+                    attachment => Att
+                }),
                 couch_log:error("~p from couch_att:fetch(data, ~p)", [Else, Att]),
                 Monitors
         end
diff --git a/src/chttpd/src/chttpd_handlers.erl b/src/chttpd/src/chttpd_handlers.erl
index ce47820..d4b7a7d 100644
--- a/src/chttpd/src/chttpd_handlers.erl
+++ b/src/chttpd/src/chttpd_handlers.erl
@@ -22,6 +22,7 @@
 -define(SERVICE_ID, chttpd_handlers).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 %% ------------------------------------------------------------------
 %% API Function Definitions
@@ -45,6 +46,12 @@ handler_info(HttpReq) ->
     try
         select(collect(handler_info, [Method, PathParts, HttpReq]), Default)
     catch Type:Reason:Stack ->
+        ?LOG_ERROR(#{
+            id => get(nonce),
+            result => Type,
+            details => Reason,
+            stack => Stack
+        }),
         couch_log:error("~s :: handler_info failure for ~p : ~p:~p :: ~p", [
                 ?MODULE,
                 get(nonce),
diff --git a/src/chttpd/src/chttpd_stats.erl b/src/chttpd/src/chttpd_stats.erl
index fa2036e..1862278 100644
--- a/src/chttpd/src/chttpd_stats.erl
+++ b/src/chttpd/src/chttpd_stats.erl
@@ -12,6 +12,7 @@
 
 -module(chttpd_stats).
 
+-include_lib("kernel/include/logger.hrl").
 
 -export([
     init/1,
@@ -62,12 +63,18 @@ report(HttpResp) ->
                 ok
         end
     catch T:R:S ->
+        ?LOG_ERROR(#{
+            what => stats_report_failure,
+            tag => T,
+            details => R,
+            stacktrace => S
+        }),
         Fmt = "Failed to report chttpd request stats: ~p:~p ~p",
         couch_log:error(Fmt, [T, R, S])
     end.
 
 
-report(HttpResp, #st{reporter = undefined}) ->
+report(_HttpResp, #st{reporter = undefined}) ->
     ok;
 
 report(HttpResp, #st{reporter = Reporter} = St) ->
diff --git a/src/chttpd/src/chttpd_sup.erl b/src/chttpd/src/chttpd_sup.erl
index 8b51e6c..44eeb7a 100644
--- a/src/chttpd/src/chttpd_sup.erl
+++ b/src/chttpd/src/chttpd_sup.erl
@@ -22,6 +22,8 @@
 
 -export([handle_config_change/5, handle_config_terminate/3]).
 
+-include_lib("kernel/include/logger.hrl").
+
 %% Helper macro for declaring children of supervisor
 -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 100, Type, [I]}).
 
@@ -33,6 +35,7 @@ start_link() ->
     supervisor:start_link({local,?MODULE}, ?MODULE, Arg).
 
 init(disabled) ->
+    ?LOG_NOTICE(#{what => http_api_disabled}),
     couch_log:notice("~p : api_frontend disabled", [?MODULE]),
     {ok, {{one_for_one, 3, 10}, []}};
 
@@ -99,6 +102,13 @@ append_if_set({Key, Value}, Opts) when Value > 0 ->
 append_if_set({_Key, 0}, Opts) ->
     Opts;
 append_if_set({Key, Value}, Opts) ->
+    ?LOG_ERROR(#{
+        what => invalid_config_setting,
+        section => chttpd_auth_cache,
+        key => Key,
+        value => Value,
+        details => "value must be a positive integer"
+    }),
     couch_log:error(
         "The value for `~s` should be string convertable "
         "to integer which is >= 0 (got `~p`)", [Key, Value]),
diff --git a/src/couch/src/couch_drv.erl b/src/couch/src/couch_drv.erl
index f2ff2ac..002facd 100644
--- a/src/couch/src/couch_drv.erl
+++ b/src/couch/src/couch_drv.erl
@@ -19,6 +19,7 @@
 -export([start_link/0]).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 start_link() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
@@ -29,6 +30,7 @@ init([]) ->
     ok ->
         {ok, nil};
     {error, already_loaded} ->
+        ?LOG_INFO(#{what => reload_couch_icu_driver}),
         couch_log:info("~p reloading couch_icu_driver", [?MODULE]),
         ok = erl_ddll:reload(LibDir, "couch_icu_driver"),
         {ok, nil};
diff --git a/src/couch/src/couch_flags_config.erl b/src/couch/src/couch_flags_config.erl
index 104a482..883fe38 100644
--- a/src/couch/src/couch_flags_config.erl
+++ b/src/couch/src/couch_flags_config.erl
@@ -13,6 +13,8 @@
 % This module implements {flags, config} data provider
 -module(couch_flags_config).
 
+-include_lib("kernel/include/logger.hrl").
+
 -export([
     enable/2,
     data/0,
@@ -80,50 +82,53 @@ data(Config) ->
 -spec parse_rules([{Key :: string(), Value :: string()}]) -> [rule()].
 
 parse_rules(Config) ->
-    lists:filtermap(fun({K, V}) ->
-        case parse_rule(K, V) of
-            {error, {Format, Args}} ->
-                couch_log:error(Format, Args),
-                false;
-            Rule ->
-                {true, Rule}
-        end
-    end, Config).
-
--spec parse_rule(Key :: string(), Value :: string()) ->
-    rule()
-    | {error, Reason :: term()}.
-
-parse_rule(Key, "true")  ->
-    parse_flags(binary:split(list_to_binary(Key), <<"||">>), true);
-parse_rule(Key, "false") ->
-    parse_flags(binary:split(list_to_binary(Key), <<"||">>), false);
+    lists:filtermap(fun({K, V}) -> parse_rule(K, V) end, Config).
+
+-spec parse_rule(Key :: string(), Value :: string()) -> {true, rule()} | false.
+
+parse_rule(Key, Value) when Value =:= "true" orelse Value =:= "false" ->
+    case binary:split(list_to_binary(Key), <<"||">>) of
+        [FlagsBin, PatternBin] ->
+            parse_flags([FlagsBin, PatternBin], list_to_atom(Value));
+        _ ->
+            ?LOG_ERROR(#{
+                what => invalid_flag_setting,
+                key => Key,
+                value => Value,
+                details => "key must be in the form of `[flags]||pattern`"
+            }),
+            false
+        end;
 parse_rule(Key, Value) ->
-    Reason = {
-        "Expected value for the `~p` either `true` or `false`, (got ~p)",
-        [Key, Value]
-    },
-    {error, Reason}.
+    ?LOG_ERROR(#{
+        what => invalid_flag_setting,
+        key => Key,
+        value => Value,
+        details => "value must be a boolean"
+    }),
+    false.
 
--spec parse_flags([binary()], Value :: boolean()) ->
-    rule() | {error, Reason :: term()}.
+-spec parse_flags([binary()], Value :: boolean()) -> {true, rule()} | false.
 
 parse_flags([FlagsBin, PatternBin], Value) ->
     case {parse_flags_term(FlagsBin), Value} of
-        {{error, _} = Error, _} ->
-            Error;
+        {{error, Errors}, _} ->
+            lists:foreach(fun(Error) ->
+                ?LOG_ERROR(#{
+                    what => invalid_flag_setting,
+                    flags => FlagsBin,
+                    error => Error
+                })
+            end, Errors),
+            false;
         {Flags, true} ->
-            {parse_pattern(PatternBin), Flags, []};
+            {true, {parse_pattern(PatternBin), Flags, []}};
         {Flags, false} ->
-            {parse_pattern(PatternBin), [], Flags}
-    end;
-parse_flags(_Tokens, _) ->
-    couch_log:error(
-      "Key should be in the form of `[flags]||pattern` (got ~s)", []),
-    false.
+            {true, {parse_pattern(PatternBin), [], Flags}}
+    end.
 
 -spec parse_flags_term(Flags :: binary()) ->
-    [flag_id()] | {error, Reason :: term()}.
+    [flag_id()] | {error, Failures :: [term()]}.
 
 parse_flags_term(FlagsBin) ->
     {Flags, Errors} = lists:splitwith(fun erlang:is_atom/1,
@@ -132,10 +137,7 @@ parse_flags_term(FlagsBin) ->
        [] ->
            lists:usort(Flags);
        _ ->
-           {error, {
-               "Cannot parse list of tags: ~n~p",
-               Errors
-           }}
+           {error, Errors}
     end.
 
 split_by_comma(Binary) ->
diff --git a/src/couch/src/couch_httpd_auth.erl b/src/couch/src/couch_httpd_auth.erl
index 7d728e6..b740220 100644
--- a/src/couch/src/couch_httpd_auth.erl
+++ b/src/couch/src/couch_httpd_auth.erl
@@ -15,6 +15,7 @@
 -compile(tuple_calls).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -export([party_mode_handler/1]).
 
@@ -212,6 +213,12 @@ get_configured_claims() ->
     Re = "((?<key1>[a-z]+)|{(?<key2>[a-z]+)\s*,\s*\"(?<val>[^\"]+)\"})",
     case re:run(Claims, Re, [global, {capture,  [key1, key2, val], binary}]) of
         nomatch when Claims /= "" ->
+            ?LOG_ERROR(#{
+                what => invalid_config_setting,
+                section => jwt_auth,
+                key => required_claims,
+                value => Claims
+            }),
             couch_log:error("[jwt_auth] required_claims is set to an invalid value.", []),
             throw({misconfigured_server, <<"JWT is not configured correctly">>});
         nomatch ->
@@ -246,6 +253,7 @@ cookie_authentication_handler(#httpd{mochi_req=MochiReq}=Req, AuthModule) ->
         CurrentTime = make_cookie_time(),
         case config:get("couch_httpd_auth", "secret", undefined) of
         undefined ->
+            ?LOG_DEBUG(#{what => cookie_auth_secret_undefined}),
             couch_log:debug("cookie auth secret is not set",[]),
             Req;
         SecretStr ->
@@ -265,6 +273,10 @@ cookie_authentication_handler(#httpd{mochi_req=MochiReq}=Req, AuthModule) ->
                         case couch_passwords:verify(ExpectedHash, Hash) of
                             true ->
                                 TimeLeft = TimeStamp + Timeout - CurrentTime,
+                                ?LOG_DEBUG(#{
+                                    what => successful_cookie_auth,
+                                    username => User
+                                }),
                                 couch_log:debug("Successful cookie auth as: ~p",
                                                 [User]),
                                 Req#httpd{user_ctx=#user_ctx{
@@ -338,6 +350,7 @@ handle_session_req(#httpd{method='POST', mochi_req=MochiReq}=Req, AuthModule) ->
     end,
     UserName = ?l2b(extract_username(Form)),
     Password = ?l2b(couch_util:get_value("password", Form, "")),
+    ?LOG_DEBUG(#{what => login_attempt, user => UserName}),
     couch_log:debug("Attempt Login: ~s",[UserName]),
     {ok, UserProps, _AuthCtx} = case AuthModule:get_user_creds(Req, UserName) of
         nil -> {ok, [], nil};
@@ -501,6 +514,13 @@ same_site() ->
         "lax" -> [{same_site, lax}];
         "strict" -> [{same_site, strict}];
         _ ->
+            ?LOG_ERROR(#{
+                what => invalid_config_setting,
+                section => couch_httpd_auth,
+                key => same_site,
+                value => SameSite,
+                details => "value must be one of `none`, `lax`, `strict`"
+            }),
             couch_log:error("invalid config value couch_httpd_auth.same_site: ~p ",[SameSite]),
             []
     end.
@@ -561,5 +581,10 @@ integer_to_binary(Int, Len) when is_integer(Int), is_integer(Len) ->
 
 authentication_warning(#httpd{mochi_req = Req}, User) ->
     Peer = Req:get(peer),
+    ?LOG_WARNING(#{
+        what => authentication_failure,
+        user => User,
+        peer => Peer
+    }),
     couch_log:warning("~p: Authentication failed for user ~s from ~s",
         [?MODULE, User, Peer]).
diff --git a/src/couch/src/couch_httpd_multipart.erl b/src/couch/src/couch_httpd_multipart.erl
index 33795a3..7e6e7d6 100644
--- a/src/couch/src/couch_httpd_multipart.erl
+++ b/src/couch/src/couch_httpd_multipart.erl
@@ -22,6 +22,7 @@
 ]).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 decode_multipart_stream(ContentType, DataFun, Ref) ->
     Parent = self(),
@@ -45,10 +46,20 @@ decode_multipart_stream(ContentType, DataFun, Ref) ->
     {'DOWN', ParserRef, _, _, normal} ->
         ok;
     {'DOWN', ParserRef, process, Parser, {{nocatch, {Error, Msg}}, _}} ->
+        ?LOG_ERROR(#{
+            what => multipart_streamer_failure,
+            ref => ParserRef,
+            details => Msg
+        }),
         couch_log:error("Multipart streamer ~p died with reason ~p",
                         [ParserRef, Msg]),
         throw({Error, Msg});
     {'DOWN', ParserRef, _, _, Reason} ->
+        ?LOG_ERROR(#{
+            what => multipart_streamer_failure,
+            ref => ParserRef,
+            details => Reason
+        }),
         couch_log:error("Multipart streamer ~p died with reason ~p",
                         [ParserRef, Reason]),
         throw({error, Reason})
diff --git a/src/couch/src/couch_httpd_vhost.erl b/src/couch/src/couch_httpd_vhost.erl
index 574dba9..3d6b4da 100644
--- a/src/couch/src/couch_httpd_vhost.erl
+++ b/src/couch/src/couch_httpd_vhost.erl
@@ -27,6 +27,7 @@
 -export([handle_config_change/5, handle_config_terminate/3]).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(SEPARATOR, $\/).
 -define(MATCH_ALL, {bind, '*'}).
@@ -146,6 +147,11 @@ redirect_to_vhost(MochiReq, VhostTarget) ->
     Path = MochiReq:get(raw_path),
     Target = append_path(VhostTarget, Path),
 
+    ?LOG_DEBUG(#{
+        what => vhost_redirect,
+        raw_path => Path,
+        target => Target
+    }),
     couch_log:debug("Vhost Target: '~p'~n", [Target]),
 
     Headers = mochiweb_headers:enter("x-couchdb-vhost-path", Path,
diff --git a/src/couch/src/couch_proc_manager.erl b/src/couch/src/couch_proc_manager.erl
index 3faef09..4627a9f 100644
--- a/src/couch/src/couch_proc_manager.erl
+++ b/src/couch/src/couch_proc_manager.erl
@@ -41,6 +41,7 @@
 ]).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(PROCS, couch_proc_manager_procs).
 -define(WAITERS, couch_proc_manager_waiters).
diff --git a/src/couch/src/couch_sup.erl b/src/couch/src/couch_sup.erl
index 6e7ef98..7a1afae 100644
--- a/src/couch/src/couch_sup.erl
+++ b/src/couch/src/couch_sup.erl
@@ -25,6 +25,7 @@
 
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 start_link() ->
@@ -93,6 +94,11 @@ assert_admins() ->
     couch_log:info("Preflight check: Asserting Admin Account~n", []),
     case {config:get("admins"), os:getenv("COUCHDB_TEST_ADMIN_PARTY_OVERRIDE")} of
         {[], false} ->
+            ?LOG_INFO(#{
+                what => admin_account_missing,
+                details => "No admin account found, aborting startup. Please configure "
+                    "an admin account in your local.ini file."
+            }),
             couch_log:info("~n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%~n"
                           ++ "  No Admin Account Found, aborting startup.                  ~n"
                           ++ "  Please configure an admin account in your local.ini file.  ~n"
@@ -104,6 +110,11 @@ assert_admins() ->
     end.
 
 send_no_admin_account_error_message() ->
+    ?LOG_ERROR(#{
+        what => admin_account_missing,
+        details => "No admin account configured. Please configure an admin "
+            "account in your local.ini file and restart CouchDB."
+    }),
     couch_log:error("No Admin Account configured."
         ++ " Please configure an Admin Account in your local.ini file and restart CouchDB.~n", []),
     FiveMinutes = 5 * 1000 * 60,
@@ -118,21 +129,37 @@ maybe_launch_admin_annoyance_reporter() ->
 
 
 notify_starting() ->
+    ?LOG_INFO(#{
+        what => starting_couchdb,
+        version => couch_server:get_version()
+    }),
     couch_log:info("Apache CouchDB ~s is starting.~n", [
         couch_server:get_version()
     ]).
 
 
 notify_started() ->
+    ?LOG_INFO(#{
+        what => starting_couchdb_complete,
+        time_to_relax => true
+    }),
     couch_log:info("Apache CouchDB has started. Time to relax.~n", []).
 
 
 notify_error(Error) ->
+    ?LOG_ERROR(#{
+        what => error_on_startup,
+        details => Error
+    }),
     couch_log:error("Error starting Apache CouchDB:~n~n    ~p~n~n", [Error]).
 
 
 notify_uris() ->
     lists:foreach(fun(Uri) ->
+        ?LOG_INFO(#{
+            what => couchdb_listener_started,
+            uri => Uri
+        }),
         couch_log:info("Apache CouchDB has started on ~s", [Uri])
     end, get_uris()).
 
@@ -193,7 +220,12 @@ write_file(FileName, Contents) ->
         ok ->
             ok;
         {error, Reason} ->
+            ?LOG_ERROR(#{
+                what => file_write_failure,
+                filename => FileName,
+                error => file:format_error(Reason)
+            }),
             Args = [FileName, file:format_error(Reason)],
-            couch_log:error("Failed ot write ~s :: ~s", Args),
+            couch_log:error("Failed to write ~s :: ~s", Args),
             throw({error, Reason})
     end.
diff --git a/src/couch_expiring_cache/src/couch_expiring_cache_fdb.erl b/src/couch_expiring_cache/src/couch_expiring_cache_fdb.erl
index fe37a7c..ebc97b9 100644
--- a/src/couch_expiring_cache/src/couch_expiring_cache_fdb.erl
+++ b/src/couch_expiring_cache/src/couch_expiring_cache_fdb.erl
@@ -27,6 +27,7 @@
 
 -include_lib("fabric/include/fabric2.hrl").
 -include_lib("couch_expiring_cache/include/couch_expiring_cache.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 % Data model
@@ -107,6 +108,7 @@ get_range_to(Name, EndTS, Limit) when Limit > 0 ->
         fun(Tx, PK, _XK, Key, _ExpiresTS, Acc) ->
             case get_val(Tx, PK) of
                 not_found ->
+                    ?LOG_ERROR(#{what => missing_key, key => Key}),
                     couch_log:error("~p:entry missing Key: ~p", [?MODULE, Key]),
                     Acc;
                 Val ->
diff --git a/src/couch_expiring_cache/src/couch_expiring_cache_server.erl b/src/couch_expiring_cache/src/couch_expiring_cache_server.erl
index 74c432e..9c0c899 100644
--- a/src/couch_expiring_cache/src/couch_expiring_cache_server.erl
+++ b/src/couch_expiring_cache/src/couch_expiring_cache_server.erl
@@ -37,6 +37,7 @@
 
 
 -include_lib("couch_expiring_cache/include/couch_expiring_cache.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 start_link(Name, Opts) when is_atom(Name) ->
@@ -96,6 +97,10 @@ handle_info(remove_expired, St) ->
 
 handle_info({Ref, ready}, St) when is_reference(Ref) ->
     % Prevent crashing server and application
+    ?LOG_ERROR(#{
+        what => spurious_future_ready,
+        ref => Ref
+    }),
     LogMsg = "~p : spurious erlfdb future ready message ~p",
     couch_log:error(LogMsg, [?MODULE, Ref]),
     {noreply, St};
diff --git a/src/couch_jobs/src/couch_jobs_activity_monitor.erl b/src/couch_jobs/src/couch_jobs_activity_monitor.erl
index d5dfa41..ef1ce1e 100644
--- a/src/couch_jobs/src/couch_jobs_activity_monitor.erl
+++ b/src/couch_jobs/src/couch_jobs_activity_monitor.erl
@@ -30,6 +30,7 @@
 
 
 -include("couch_jobs.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -record(st, {
@@ -74,6 +75,12 @@ handle_info(check_activity, St) ->
     catch
         error:{erlfdb_error, Err} when ?ERLFDB_IS_RETRYABLE(Err) orelse
                 Err =:= ?ERLFDB_TRANSACTION_TIMED_OUT ->
+            ?LOG_ERROR(#{
+                what => erlfdb_error,
+                job_type => St#st.type,
+                error_code => Err,
+                details => "possible overload condition"
+            }),
             LogMsg = "~p : type:~p got ~p error, possibly from overload",
             couch_log:error(LogMsg, [?MODULE, St#st.type, Err]),
             St
@@ -84,6 +91,10 @@ handle_info(check_activity, St) ->
 handle_info({Ref, ready}, St) when is_reference(Ref) ->
     % Don't crash out couch_jobs_server and the whole application would need to
     % eventually do proper cleanup in erlfdb:wait timeout code.
+    ?LOG_ERROR(#{
+        what => spurious_future_ready,
+        ref => Ref
+    }),
     LogMsg = "~p : spurious erlfdb future ready message ~p",
     couch_log:error(LogMsg, [?MODULE, Ref]),
     {noreply, St};
diff --git a/src/couch_jobs/src/couch_jobs_notifier.erl b/src/couch_jobs/src/couch_jobs_notifier.erl
index db5d5e0..fea7084 100644
--- a/src/couch_jobs/src/couch_jobs_notifier.erl
+++ b/src/couch_jobs/src/couch_jobs_notifier.erl
@@ -33,6 +33,7 @@
 
 
 -include("couch_jobs.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -define(TYPE_MONITOR_HOLDOFF_DEFAULT, 50).
@@ -121,6 +122,10 @@ handle_info({type_updated, VS}, St) ->
 handle_info({Ref, ready}, St) when is_reference(Ref) ->
     % Don't crash out couch_jobs_server and the whole application would need to
     % eventually do proper cleanup in erlfdb:wait timeout code.
+    ?LOG_ERROR(#{
+        what => spurious_future_ready,
+        ref => Ref
+    }),
     LogMsg = "~p : spurious erlfdb future ready message ~p",
     couch_log:error(LogMsg, [?MODULE, Ref]),
     {noreply, St};
diff --git a/src/couch_jobs/src/couch_jobs_server.erl b/src/couch_jobs/src/couch_jobs_server.erl
index 2e03c7d..5f9def6 100644
--- a/src/couch_jobs/src/couch_jobs_server.erl
+++ b/src/couch_jobs/src/couch_jobs_server.erl
@@ -14,6 +14,7 @@
 
 -behaviour(gen_server).
 
+-include_lib("kernel/include/logger.hrl").
 
 -export([
     start_link/0,
@@ -92,6 +93,11 @@ handle_info(check_types, St) ->
     {noreply, St};
 
 handle_info({'DOWN', _Ref, process, Pid, Reason}, St) ->
+    ?LOG_ERROR(#{
+        what => unknown_process_crash,
+        pid => Pid,
+        details => Reason
+    }),
     LogMsg = "~p : process ~p exited with ~p",
     couch_log:error(LogMsg, [?MODULE, Pid, Reason]),
     {stop, {unexpected_process_exit, Pid, Reason}, St};
@@ -99,6 +105,10 @@ handle_info({'DOWN', _Ref, process, Pid, Reason}, St) ->
 handle_info({Ref, ready}, St) when is_reference(Ref) ->
     % Don't crash out couch_jobs_server and the whole application would need to
     % eventually do proper cleanup in erlfdb:wait timeout code.
+    ?LOG_ERROR(#{
+        what => spurious_future_ready,
+        ref => Ref
+    }),
     LogMsg = "~p : spurious erlfdb future ready message ~p",
     couch_log:error(LogMsg, [?MODULE, Ref]),
     {noreply, St};
@@ -171,6 +181,7 @@ fdb_types() ->
         end)
     catch
         error:{timeout, _} ->
+            ?LOG_WARNING(#{what => fdb_connection_timeout}),
             couch_log:warning("~p : Timed out connecting to FDB", [?MODULE]),
             []
     end.
diff --git a/src/couch_js/src/couch_js_native_process.erl b/src/couch_js/src/couch_js_native_process.erl
index d5ed3f9..8add3d5 100644
--- a/src/couch_js/src/couch_js_native_process.erl
+++ b/src/couch_js/src/couch_js_native_process.erl
@@ -56,6 +56,7 @@
 }).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 start_link() ->
     gen_server:start_link(?MODULE, [], []).
@@ -80,6 +81,11 @@ handle_call({set_timeout, TimeOut}, _From, State) ->
     {reply, ok, State#evstate{timeout=TimeOut}, State#evstate.idle};
 
 handle_call({prompt, Data}, _From, State) ->
+    ?LOG_DEBUG(#{
+        what => prompt,
+        in => native_process,
+        msg => ?JSON_ENCODE(Data)
+    }),
     couch_log:debug("Prompt native qs: ~s",[?JSON_ENCODE(Data)]),
     {NewState, Resp} = try run(State, to_binary(Data)) of
         {S, R} -> {S, R}
@@ -211,6 +217,11 @@ run(#evstate{ddocs=DDocs}=State, [<<"ddoc">>, DDocId | Rest]) ->
     DDoc = load_ddoc(DDocs, DDocId),
     ddoc(State, DDoc, Rest);
 run(_, Unknown) ->
+    ?LOG_ERROR(#{
+        what => unknown_command,
+        in => native_process,
+        cmd => Unknown
+    }),
     couch_log:error("Native Process: Unknown command: ~p~n", [Unknown]),
     throw({error, unknown_command}).
 
@@ -237,7 +248,13 @@ ddoc(State, {_, Fun}, [<<"filters">>|_], [Docs, Req]) ->
         case catch Fun(Doc, Req) of
         true -> true;
         false -> false;
-        {'EXIT', Error} -> couch_log:error("~p", [Error])
+        {'EXIT', Error} ->
+            ?LOG_ERROR(#{
+                what => filter_fun_crash,
+                in => native_process,
+                details => Error
+            }),
+            couch_log:error("~p", [Error])
         end
     end,
     Resp = lists:map(FilterFunWrapper, Docs),
@@ -249,7 +266,13 @@ ddoc(State, {_, Fun}, [<<"views">>|_], [Docs]) ->
         ok -> false;
         false -> false;
         [_|_] -> true;
-        {'EXIT', Error} -> couch_log:error("~p", [Error])
+        {'EXIT', Error} ->
+            ?LOG_ERROR(#{
+                what => view_fun_crash,
+                in => native_process,
+                details => Error
+            }),
+            couch_log:error("~p", [Error])
         end
     end,
     Resp = lists:map(MapFunWrapper, Docs),
@@ -318,6 +341,12 @@ bindings(State, Sig, DDoc) ->
     Self = self(),
 
     Log = fun(Msg) ->
+        ?LOG_INFO(#{
+            what => user_defined_log,
+            in => native_process,
+            signature => Sig,
+            msg => Msg
+        }),
         couch_log:info(Msg, [])
     end,
 
@@ -393,6 +422,13 @@ makefun(_State, Source, BindFuns) when is_list(BindFuns) ->
         {ok, [ParsedForm]} ->
             ParsedForm;
         {error, {LineNum, _Mod, [Mesg, Params]}}=Error ->
+            ?LOG_ERROR(#{
+                what => syntax_error,
+                in => native_process,
+                line => LineNum,
+                details => Mesg,
+                parameters => Params
+            }),
             couch_log:error("Syntax error on line: ~p~n~s~p~n",
                             [LineNum, Mesg, Params]),
             throw(Error)
diff --git a/src/couch_js/src/couch_js_os_process.erl b/src/couch_js/src/couch_js_os_process.erl
index 883bc8f..181ca09 100644
--- a/src/couch_js/src/couch_js_os_process.erl
+++ b/src/couch_js/src/couch_js_os_process.erl
@@ -20,6 +20,7 @@
 -export([init/1, terminate/2, handle_call/3, handle_cast/2, handle_info/2, code_change/3]).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(PORT_OPTIONS, [stream, {line, 4096}, binary, exit_status, hide]).
 
@@ -55,6 +56,12 @@ prompt(Pid, Data) ->
         {ok, Result} ->
             Result;
         Error ->
+            ?LOG_ERROR(#{
+                what => communication_error,
+                in => os_process,
+                pid => Pid,
+                details => Error
+            }),
             couch_log:error("OS Process Error ~p :: ~p",[Pid,Error]),
             throw(Error)
     end.
@@ -95,12 +102,24 @@ readline(#os_proc{port = Port} = OsProc, Acc) ->
 % Standard JSON functions
 writejson(OsProc, Data) when is_record(OsProc, os_proc) ->
     JsonData = ?JSON_ENCODE(Data),
+    ?LOG_DEBUG(#{
+        what => writeline,
+        in => os_process,
+        port => OsProc#os_proc.port,
+        data => JsonData
+    }),
     couch_log:debug("OS Process ~p Input  :: ~s",
                     [OsProc#os_proc.port, JsonData]),
     true = writeline(OsProc, JsonData).
 
 readjson(OsProc) when is_record(OsProc, os_proc) ->
     Line = iolist_to_binary(readline(OsProc)),
+    ?LOG_DEBUG(#{
+        what => readline,
+        in => os_process,
+        port => OsProc#os_proc.port,
+        data => Line
+    }),
     couch_log:debug("OS Process ~p Output :: ~s", [OsProc#os_proc.port, Line]),
     try
         % Don't actually parse the whole JSON. Just try to see if it's
@@ -115,12 +134,24 @@ readjson(OsProc) when is_record(OsProc, os_proc) ->
         case ?JSON_DECODE(Line) of
         [<<"log">>, Msg] when is_binary(Msg) ->
             % we got a message to log. Log it and continue
+            ?LOG_INFO(#{
+                what => user_defined_log,
+                in => os_process,
+                port => OsProc#os_proc.port,
+                msg => Msg
+            }),
             couch_log:info("OS Process ~p Log :: ~s",
                            [OsProc#os_proc.port, Msg]),
             readjson(OsProc);
         [<<"error">>, Id, Reason] ->
             throw({error, {couch_util:to_existing_atom(Id),Reason}});
         [<<"fatal">>, Id, Reason] ->
+            ?LOG_INFO(#{
+                what => fatal_error,
+                in => os_process,
+                port => OsProc#os_proc.port,
+                details => Reason
+            }),
             couch_log:info("OS Process ~p Fatal Error :: ~s ~p",
                 [OsProc#os_proc.port, Id, Reason]),
             throw({couch_util:to_existing_atom(Id),Reason});
@@ -163,6 +194,11 @@ init([Command, Options, PortOptions]) ->
     },
     KillCmd = iolist_to_binary(readline(BaseProc)),
     Pid = self(),
+    ?LOG_DEBUG(#{
+        what => init,
+        in => os_process,
+        port => BaseProc#os_proc.port
+    }),
     couch_log:debug("OS Process Start :: ~p", [BaseProc#os_proc.port]),
     spawn(fun() ->
             % this ensure the real os process is killed when this process dies.
@@ -216,6 +252,12 @@ handle_cast({send, Data}, #os_proc{writer=Writer, idle=Idle}=OsProc) ->
         {noreply, OsProc, Idle}
     catch
         throw:OsError ->
+            ?LOG_INFO(#{
+                what => write_failure,
+                in => os_process,
+                details => OsError,
+                data => Data
+            }),
             couch_log:error("Failed sending data: ~p -> ~p", [Data, OsError]),
             {stop, normal, OsProc}
     end;
@@ -225,6 +267,11 @@ handle_cast(garbage_collect, #os_proc{idle=Idle}=OsProc) ->
 handle_cast(stop, OsProc) ->
     {stop, normal, OsProc};
 handle_cast(Msg, #os_proc{idle=Idle}=OsProc) ->
+    ?LOG_DEBUG(#{
+        what => unknown_message,
+        in => os_process,
+        data => Msg
+    }),
     couch_log:debug("OS Proc: Unknown cast: ~p", [Msg]),
     {noreply, OsProc, Idle}.
 
@@ -233,12 +280,29 @@ handle_info(timeout, #os_proc{idle=Idle}=OsProc) ->
     erlang:garbage_collect(),
     {noreply, OsProc, Idle};
 handle_info({Port, {exit_status, 0}}, #os_proc{port=Port}=OsProc) ->
+    ?LOG_INFO(#{
+        what => normal_termination,
+        in => os_process,
+        port => Port
+    }),
     couch_log:info("OS Process terminated normally", []),
     {stop, normal, OsProc};
 handle_info({Port, {exit_status, Status}}, #os_proc{port=Port}=OsProc) ->
+    ?LOG_ERROR(#{
+        what => abnormal_termination,
+        in => os_process,
+        port => Port,
+        exit_status => Status
+    }),
     couch_log:error("OS Process died with status: ~p", [Status]),
     {stop, {exit_status, Status}, OsProc};
 handle_info(Msg, #os_proc{idle=Idle}=OsProc) ->
+    ?LOG_DEBUG(#{
+        what => unexpected_message,
+        in => os_process,
+        port => OsProc#os_proc.port,
+        msg => Msg
+    }),
     couch_log:debug("OS Proc: Unknown info: ~p", [Msg]),
     {noreply, OsProc, Idle}.
 
diff --git a/src/couch_js/src/couch_js_proc_manager.erl b/src/couch_js/src/couch_js_proc_manager.erl
index d9c3efc..0f55ced 100644
--- a/src/couch_js/src/couch_js_proc_manager.erl
+++ b/src/couch_js/src/couch_js_proc_manager.erl
@@ -40,6 +40,7 @@
 ]).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(PROCS, couch_js_proc_manager_procs).
 -define(WAITERS, couch_js_proc_manager_waiters).
@@ -197,6 +198,7 @@ handle_cast({os_proc_idle, Pid}, #state{counts=Counts}=State) ->
         [#proc_int{client=undefined, lang=Lang}=Proc] ->
             case dict:find(Lang, Counts) of
                 {ok, Count} when Count >= State#state.soft_limit ->
+                    ?LOG_INFO(#{what => close_idle_os_process, pid => Pid}),
                     couch_log:info("Closing idle OS Process: ~p", [Pid]),
                     remove_proc(State, Proc);
                 {ok, _} ->
@@ -239,6 +241,7 @@ handle_info({'EXIT', Pid, spawn_error}, State) ->
     {noreply, flush_waiters(NewState, Lang)};
 
 handle_info({'EXIT', Pid, Reason}, State) ->
+    ?LOG_INFO(#{what => os_process_failure, pid => Pid, details => Reason}),
     couch_log:info("~p ~p died ~p", [?MODULE, Pid, Reason]),
     case ets:lookup(?PROCS, Pid) of
         [#proc_int{} = Proc] ->
@@ -321,6 +324,11 @@ find_proc(#client{lang = Lang, ddoc = DDoc, ddoc_key = DDocKey} = Client) ->
 find_proc(Lang, Fun) ->
     try iter_procs(Lang, Fun)
     catch error:Reason:StackTrace ->
+        ?LOG_ERROR(#{
+            what => os_process_not_available,
+            details => Reason,
+            stacktrace => StackTrace
+        }),
         couch_log:error("~p ~p ~p", [?MODULE, Reason, StackTrace]),
         {error, Reason}
     end.
diff --git a/src/couch_js/src/couch_js_query_servers.erl b/src/couch_js/src/couch_js_query_servers.erl
index 80ceb3d..7dbacc6 100644
--- a/src/couch_js/src/couch_js_query_servers.erl
+++ b/src/couch_js/src/couch_js_query_servers.erl
@@ -25,6 +25,7 @@
 -export([get_os_process/1, get_ddoc_process/2, ret_os_process/1]).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(SUMERROR, <<"The _sum function requires that map values be numbers, "
     "arrays of numbers, or objects. Objects cannot be mixed with other "
@@ -264,6 +265,12 @@ check_sum_overflow(InSize, OutSize, Sum) ->
     end.
 
 log_sum_overflow(InSize, OutSize) ->
+    ?LOG_ERROR(#{
+        what => reduce_function_overflow,
+        input_size => InSize,
+        output_size => OutSize,
+        details => "reduce output must shrink more rapidly"
+    }),
     Fmt = "Reduce output must shrink more rapidly: "
             "input size: ~b "
             "output size: ~b",
diff --git a/src/couch_replicator/src/couch_replicator.erl b/src/couch_replicator/src/couch_replicator.erl
index a690d37..a0c6d2b 100644
--- a/src/couch_replicator/src/couch_replicator.erl
+++ b/src/couch_replicator/src/couch_replicator.erl
@@ -38,6 +38,7 @@
 -include_lib("ibrowse/include/ibrowse.hrl").
 -include_lib("couch/include/couch_db.hrl").
 -include("couch_replicator.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -spec replicate({[_]}, any()) ->
@@ -287,6 +288,7 @@ cancel_replication(JobId) when is_binary(JobId) ->
             _ ->
                 JobId
         end,
+        ?LOG_NOTICE(#{what => cancel_replication, in => replicator, id => Id}),
         couch_log:notice("Canceling replication '~s'", [Id]),
         case couch_replicator_jobs:remove_job(JTx, JobId) of
             {error, not_found} ->
@@ -327,6 +329,13 @@ process_change(#{} = Db, #doc{deleted = false} = Doc) ->
                 ?ST_PENDING, null, DocState)
     end,
 
+    ?LOG_NOTICE(#{
+        what => replication_update,
+        db => DbName,
+        docid => DocId,
+        job_id => JobId,
+        job_state => DocState
+    }),
     LogMsg = "~p : replication doc update db:~s doc:~s job_id:~s doc_state:~s",
     couch_log:notice(LogMsg, [?MODULE, DbName, DocId, JobId, DocState]),
 
diff --git a/src/couch_replicator/src/couch_replicator_api_wrap.erl b/src/couch_replicator/src/couch_replicator_api_wrap.erl
index 17e5bf2..424c3ec 100644
--- a/src/couch_replicator/src/couch_replicator_api_wrap.erl
+++ b/src/couch_replicator/src/couch_replicator_api_wrap.erl
@@ -21,6 +21,7 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_views/include/couch_views.hrl").
 -include("couch_replicator_api_wrap.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -export([
     db_open/1,
@@ -178,6 +179,12 @@ open_doc_revs(#httpdb{retries = 0} = HttpDb, Id, Revs, Options, _Fun, _Acc) ->
     Url = couch_util:url_strip_password(
         couch_replicator_httpc:full_url(HttpDb, [{path,Path}, {qs,QS}])
     ),
+    ?LOG_ERROR(#{
+        what => permanent_request_failure,
+        in => replicator,
+        url => Url,
+        retries_remaining => 0
+    }),
     couch_log:error("Replication crashing because GET ~s failed", [Url]),
     exit(kaboom);
 open_doc_revs(#httpdb{} = HttpDb, Id, Revs, Options, Fun, Acc) ->
@@ -244,6 +251,13 @@ open_doc_revs(#httpdb{} = HttpDb, Id, Revs, Options, Fun, Acc) ->
                 true ->
                     throw(request_uri_too_long);
                 false ->
+                    ?LOG_INFO(#{
+                        what => request_uri_too_long,
+                        in => replicator,
+                        docid => Id,
+                        new_max_length => NewMaxLen,
+                        details => "reducing url length because of 414 response"
+                    }),
                     couch_log:info("Reducing url length to ~B because of"
                                    " 414 response", [NewMaxLen]),
                     Options1 = lists:keystore(max_url_len, 1, Options,
@@ -256,6 +270,13 @@ open_doc_revs(#httpdb{} = HttpDb, Id, Revs, Options, Fun, Acc) ->
             ),
             #httpdb{retries = Retries, wait = Wait0} = HttpDb,
             Wait = 2 * erlang:min(Wait0 * 2, ?MAX_WAIT),
+            ?LOG_NOTICE(#{
+                what => retry_request,
+                in => replicator,
+                url => Url,
+                delay => Wait / 1000,
+                details => error_reason(Else)
+            }),
             couch_log:notice("Retrying GET to ~s in ~p seconds due to error ~w",
                 [Url, Wait / 1000, error_reason(Else)]
             ),
diff --git a/src/couch_replicator/src/couch_replicator_auth_session.erl b/src/couch_replicator/src/couch_replicator_auth_session.erl
index a59c770..9526dc5 100644
--- a/src/couch_replicator/src/couch_replicator_auth_session.erl
+++ b/src/couch_replicator/src/couch_replicator_auth_session.erl
@@ -74,6 +74,7 @@
 
 -include_lib("ibrowse/include/ibrowse.hrl").
 -include_lib("couch_replicator/include/couch_replicator_api_wrap.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -type headers() :: [{string(), string()}].
@@ -156,6 +157,11 @@ handle_call({update_headers, Headers, _Epoch}, _From, State) ->
             Headers1 = [{"Cookie", Cookie} | Headers],
             {reply, {Headers1, State1#state.epoch}, State1};
         {error, Error} ->
+            ?LOG_ERROR(#{
+                what => terminate_session_auth_plugin,
+                in => replicator,
+                details => Error
+            }),
             LogMsg = "~p: Stopping session auth plugin because of error ~p",
             couch_log:error(LogMsg, [?MODULE, Error]),
             {stop, Error, State}
@@ -170,11 +176,13 @@ handle_call(stop, _From, State) ->
 
 
 handle_cast(Msg, State) ->
+    ?LOG_ERROR(#{what => unexpected_cast, in => replicator, msg => Msg}),
     couch_log:error("~p: Received un-expected cast ~p", [?MODULE, Msg]),
     {noreply, State}.
 
 
 handle_info(Msg, State) ->
+    ?LOG_ERROR(#{what => unexpected_msg, in => replicator, msg => Msg}),
     couch_log:error("~p : Received un-expected message ~p", [?MODULE, Msg]),
     {noreply, State}.
 
@@ -307,6 +315,11 @@ process_response(Code, Headers, _Epoch, State) when Code >= 200, Code < 300 ->
         {error, cookie_not_found} ->
             State;
         {error, Other} ->
+            ?LOG_ERROR(#{
+                what => cookie_parse_error,
+                in => replicator,
+                details => Other
+            }),
             LogMsg = "~p : Could not parse cookie from response headers ~p",
             couch_log:error(LogMsg, [?MODULE, Other]),
             State
diff --git a/src/couch_replicator/src/couch_replicator_changes_reader.erl b/src/couch_replicator/src/couch_replicator_changes_reader.erl
index 6adf1af..b0bcb54 100644
--- a/src/couch_replicator/src/couch_replicator_changes_reader.erl
+++ b/src/couch_replicator/src/couch_replicator_changes_reader.erl
@@ -21,6 +21,7 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_replicator/include/couch_replicator_api_wrap.hrl").
 -include("couch_replicator.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 start_link(StartSeq, #httpdb{} = Db, ChangesQueue, #{} = Options) ->
@@ -60,14 +61,23 @@ read_changes(Parent, StartSeq, Db, ChangesQueue, Options) ->
         N when N > 0 ->
             put(retries_left, N - 1),
             LastSeq = get(last_seq),
+            LogMsg = #{
+                what => retry_changes_feed,
+                in => replicator,
+                source => couch_replicator_api_wrap:db_uri(Db),
+                sequence => LastSeq,
+                retries_remaining => N
+            },
             Db2 = case LastSeq of
             StartSeq ->
+                ?LOG_NOTICE(maps:merge(LogMsg, #{delay => Db#httpdb.wait / 1000})),
                 couch_log:notice("Retrying _changes request to source database ~s"
                     " with since=~p in ~p seconds",
                     [couch_replicator_api_wrap:db_uri(Db), LastSeq, Db#httpdb.wait / 1000]),
                 ok = timer:sleep(Db#httpdb.wait),
                 Db#httpdb{wait = 2 * Db#httpdb.wait};
             _ ->
+                ?LOG_NOTICE(LogMsg),
                 couch_log:notice("Retrying _changes request to source database ~s"
                     " with since=~p", [couch_replicator_api_wrap:db_uri(Db), LastSeq]),
                 Db
@@ -82,6 +92,12 @@ read_changes(Parent, StartSeq, Db, ChangesQueue, Options) ->
 process_change(#doc_info{id = <<>>} = DocInfo, {_, Db, _, _}) ->
     % Previous CouchDB releases had a bug which allowed a doc with an empty ID
     % to be inserted into databases. Such doc is impossible to GET.
+    ?LOG_ERROR(#{
+        what => ignore_empty_docid,
+        in => replicator,
+        source => couch_replicator_api_wrap:db_uri(Db),
+        sequence => DocInfo#doc_info.high_seq
+    }),
     couch_log:error("Replicator: ignoring document with empty ID in "
         "source database `~s` (_changes sequence ~p)",
         [couch_replicator_api_wrap:db_uri(Db), DocInfo#doc_info.high_seq]);
@@ -90,6 +106,13 @@ process_change(#doc_info{id = Id} = DocInfo, {Parent, Db, ChangesQueue, _}) ->
     case is_doc_id_too_long(byte_size(Id)) of
         true ->
             SourceDb = couch_replicator_api_wrap:db_uri(Db),
+            ?LOG_ERROR(#{
+                what => doc_write_failure,
+                in => replicator,
+                source => SourceDb,
+                docid => Id,
+                details => "document ID too long"
+            }),
             couch_log:error("Replicator: document id `~s...` from source db "
                 " `~64s` is too long, ignoring.", [Id, SourceDb]),
             Stats = couch_replicator_stats:new([{doc_write_failures, 1}]),
diff --git a/src/couch_replicator/src/couch_replicator_connection.erl b/src/couch_replicator/src/couch_replicator_connection.erl
index f31baf4..ace93d5 100644
--- a/src/couch_replicator/src/couch_replicator_connection.erl
+++ b/src/couch_replicator/src/couch_replicator_connection.erl
@@ -40,6 +40,7 @@
 ]).
 
 -include_lib("ibrowse/include/ibrowse.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(DEFAULT_CLOSE_INTERVAL, 90000).
 -define(RELISTEN_DELAY, 5000).
@@ -232,6 +233,13 @@ maybe_log_worker_death(_Host, _Port, normal) ->
     ok;
 
 maybe_log_worker_death(Host, Port, Reason) ->
+    ?LOG_INFO(#{
+        what => connection_failed,
+        in => replicator,
+        host => Host,
+        port => Port,
+        details => Reason
+    }),
     ErrMsg = "Replication connection to: ~p:~p died with reason ~p",
     couch_log:info(ErrMsg, [Host, Port, Reason]).
 
diff --git a/src/couch_replicator/src/couch_replicator_docs.erl b/src/couch_replicator/src/couch_replicator_docs.erl
index f84d129..b7fa937 100644
--- a/src/couch_replicator/src/couch_replicator_docs.erl
+++ b/src/couch_replicator/src/couch_replicator_docs.erl
@@ -24,6 +24,7 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_replicator/include/couch_replicator_api_wrap.hrl").
 -include("couch_replicator.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -define(OWNER, <<"owner">>).
@@ -67,6 +68,13 @@ update_failed(null, null, null, _) ->
 
 update_failed(DbName, DbUUID, DocId, Error) ->
     Reason = error_reason(Error),
+    ?LOG_ERROR(#{
+        what => replication_failed,
+        in => replicator,
+        replicator_db => DbName,
+        replicator_doc => DocId,
+        details => Reason
+    }),
     couch_log:error("Error processing replication doc `~s` from `~s`: ~s",
         [DocId, DbName, Reason]),
     update_rep_doc(DbName, DbUUID, DocId, [
@@ -154,9 +162,17 @@ update_rep_doc(RepDbName, RepDbUUID, RepDocId, KVs, Wait)
         end
     catch
         throw:conflict ->
+            Delay = couch_rand:uniform(erlang:min(128, Wait)) * 100,
+            ?LOG_ERROR(#{
+                what => replication_doc_conflict,
+                in => replicator,
+                replication_db => RepDbName,
+                replication_doc => RepDocId,
+                retry_delay => Delay
+            }),
             Msg = "Conflict when updating replication doc `~s`. Retrying.",
             couch_log:error(Msg, [RepDocId]),
-            ok = timer:sleep(couch_rand:uniform(erlang:min(128, Wait)) * 100),
+            ok = timer:sleep(Delay),
             update_rep_doc(RepDbName, RepDbUUID, RepDocId, KVs, Wait * 2)
     end;
 
@@ -213,6 +229,13 @@ save_rep_doc(DbName, DbUUID, Doc) when is_binary(DbName), is_binary(DbUUID) ->
         % updating replication documents. Avoid crashing replicator and thus
         % preventing all other replication jobs on the node from running.
         throw:{forbidden, Reason} ->
+            ?LOG_ERROR(#{
+                what => replication_doc_update_forbidden,
+                in => replicator,
+                replication_db => DbName,
+                replication_doc => Doc#doc.id,
+                details => Reason
+            }),
             Msg = "~p VDU or BDU function preventing doc update to ~s ~s ~p",
             couch_log:error(Msg, [?MODULE, DbName, Doc#doc.id, Reason]),
             {ok, forbidden}
diff --git a/src/couch_replicator/src/couch_replicator_httpc.erl b/src/couch_replicator/src/couch_replicator_httpc.erl
index 52baa39..d45a019 100644
--- a/src/couch_replicator/src/couch_replicator_httpc.erl
+++ b/src/couch_replicator/src/couch_replicator_httpc.erl
@@ -15,6 +15,7 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("ibrowse/include/ibrowse.hrl").
 -include_lib("couch_replicator/include/couch_replicator_api_wrap.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -export([setup/1]).
 -export([send_req/3]).
@@ -55,6 +56,12 @@ setup(Db) ->
         {error, Error} ->
             LogMsg = "~p: auth plugin initialization failed ~p ~p",
             LogUrl = couch_util:url_strip_password(Url),
+            ?LOG_ERROR(#{
+                what => auth_plugin_initialization_failure,
+                in => replicator,
+                db => LogUrl,
+                details => Error
+            }),
             couch_log:error(LogMsg, [?MODULE, LogUrl, Error]),
             throw({replication_auth_error, Error})
     end.
@@ -348,6 +355,14 @@ update_first_error_timestamp(HttpDb) ->
 log_retry_error(Params, HttpDb, Wait, Error) ->
     Method = string:to_upper(atom_to_list(get_value(method, Params, get))),
     Url = couch_util:url_strip_password(full_url(HttpDb, Params)),
+    ?LOG_NOTICE(#{
+        what => retry_request,
+        in => replicator,
+        method => Method,
+        url => Url,
+        retry_delay => Wait / 1000,
+        details => error_cause(Error)
+    }),
     couch_log:notice("Retrying ~s request to ~s in ~p seconds due to error ~s",
         [Method, Url, Wait / 1000, error_cause(Error)]).
 
@@ -360,10 +375,24 @@ report_error(_Worker, HttpDb, Params, Error) ->
 
 
 do_report_error(Url, Method, {code, Code}) ->
+    ?LOG_ERROR(#{
+        what => failed_request,
+        in => replicator,
+        method => Method,
+        url => Url,
+        status_code => Code
+    }),
     couch_log:error("Replicator, request ~s to ~p failed. The received "
         "HTTP error code is ~p", [Method, Url, Code]);
 
 do_report_error(FullUrl, Method, Error) ->
+    ?LOG_ERROR(#{
+        what => failed_request,
+        in => replicator,
+        method => Method,
+        url => FullUrl,
+        details => error_cause(Error)
+    }),
     couch_log:error("Replicator, request ~s to ~p failed due to error ~s",
         [Method, FullUrl, error_cause(Error)]).
 
diff --git a/src/couch_replicator/src/couch_replicator_job.erl b/src/couch_replicator/src/couch_replicator_job.erl
index 8cfb426..3c07fdd 100644
--- a/src/couch_replicator/src/couch_replicator_job.erl
+++ b/src/couch_replicator/src/couch_replicator_job.erl
@@ -39,6 +39,7 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_replicator/include/couch_replicator_api_wrap.hrl").
 -include("couch_replicator.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -define(LOWEST_SEQ, 0).
@@ -116,6 +117,12 @@ terminate(shutdown, #rep_state{} = State0) ->
         {ok, State2} ->
             State2;
         Error ->
+            ?LOG_ERROR(#{
+                what => checkpoint_failure,
+                in => replicator,
+                jobid => State1#rep_state.id,
+                details => Error
+            }),
             Msg = "~p : Failed last checkpoint. Job: ~p Error: ~p",
             couch_log:error(Msg, [?MODULE, State1#rep_state.id, Error]),
             State1
@@ -127,9 +134,20 @@ terminate(shutdown, #rep_state{} = State0) ->
 terminate({shutdown, Error}, {init_error, Stack}) ->
     % Termination in init, before the job had initialized
     case Error of
-        max_backoff -> couch_log:warning("~p job backed off", [?MODULE]);
-        finished -> couch_log:notice("~p job finished in init", [?MODULE]);
-        _ -> couch_log:error("~p job failed ~p ~p", [?MODULE, Error, Stack])
+        max_backoff ->
+            ?LOG_WARNING(#{what => job_backoff, in => replicator}),
+            couch_log:warning("~p job backed off", [?MODULE]);
+        finished ->
+            ?LOG_NOTICE(#{what => job_finished_during_init, in => replicator}),
+            couch_log:notice("~p job finished in init", [?MODULE]);
+        _ ->
+            ?LOG_ERROR(#{
+                what => job_failure,
+                in => replicator,
+                details => Error,
+                stacktrace => Stack
+            }),
+            couch_log:error("~p job failed ~p ~p", [?MODULE, Error, Stack])
     end,
     ok;
 
@@ -139,6 +157,11 @@ terminate({shutdown, finished}, #rep_state{} = State) ->
 
 terminate({shutdown, halt}, #rep_state{} = State) ->
     % Job is re-enqueued and possibly already running somewhere else
+    ?LOG_ERROR(#{
+        what => job_halted,
+        in => replicator,
+        jobid => State#rep_state.id
+    }),
     couch_log:error("~p job ~p halted", [?MODULE, State#rep_state.id]),
     ok = close_endpoints(State);
 
@@ -155,6 +178,14 @@ terminate(Reason0, #rep_state{} = State0) ->
         source_name = Source,
         target_name = Target
     } = State,
+    ?LOG_ERROR(#{
+        what => job_failure,
+        in => replicator,
+        replication_id => RepId,
+        source => Source,
+        target => Target,
+        details => Reason
+    }),
     couch_log:error("Replication `~s` (`~s` -> `~s`) failed: ~p",
         [RepId, Source, Target, Reason]),
     ok = reschedule_on_error(undefined, Job, JobData, Reason),
@@ -189,6 +220,21 @@ handle_call({report_seq_done, Seq, StatsInc}, From, #rep_state{} = State) ->
         _ ->
             NewThroughSeq0
     end,
+    ?LOG_DEBUG(#{
+        what => progress_report,
+        in => replicator,
+        old => #{
+            highest_seq_done => HighestDone,
+            current_through_seq => ThroughSeq,
+            seqs_in_progress => SeqsInProgress
+        },
+        new => #{
+            highest_seq_done => NewHighestDone,
+            current_through_seq => NewThroughSeq,
+            seqs_in_progress => NewSeqsInProgress
+        },
+        worker_reported_seq => Seq
+    }),
     couch_log:debug("Worker reported seq ~p, through seq was ~p, "
         "new through seq is ~p, highest seq done was ~p, "
         "new highest seq done is ~p~n"
@@ -251,10 +297,12 @@ handle_info(shutdown, St) ->
     {stop, shutdown, St};
 
 handle_info({'EXIT', Pid, max_backoff}, State) ->
+    ?LOG_ERROR(#{what => max_backoff, in => replicator, pid => Pid}),
     couch_log:error("Max backoff reached child process ~p", [Pid]),
     {stop, {shutdown, max_backoff}, State};
 
 handle_info({'EXIT', Pid, {shutdown, max_backoff}}, State) ->
+    ?LOG_ERROR(#{what => max_backoff, in => replicator, pid => Pid}),
     couch_log:error("Max backoff reached child process ~p", [Pid]),
     {stop, {shutdown, max_backoff}, State};
 
@@ -273,6 +321,7 @@ handle_info({'EXIT', Pid, Reason0}, #rep_state{changes_reader=Pid} = State) ->
         Other ->
             {changes_reader_died, Other}
     end,
+    ?LOG_ERROR(#{what => changes_reader_crash, in => replicator, details => Reason}),
     couch_log:error("ChangesReader process died with reason: ~p", [Reason]),
     {stop, {shutdown, Reason}, cancel_timers(State)};
 
@@ -281,6 +330,7 @@ handle_info({'EXIT', Pid, normal}, #rep_state{changes_manager=Pid} = State) ->
 
 handle_info({'EXIT', Pid, Reason}, #rep_state{changes_manager=Pid} = State) ->
     couch_stats:increment_counter([couch_replicator, changes_manager_deaths]),
+    ?LOG_ERROR(#{what => changes_manager_crash, in => replicator, details => Reason}),
     couch_log:error("ChangesManager process died with reason: ~p", [Reason]),
     {stop, {shutdown, {changes_manager_died, Reason}}, cancel_timers(State)};
 
@@ -289,6 +339,7 @@ handle_info({'EXIT', Pid, normal}, #rep_state{changes_queue=Pid} = State) ->
 
 handle_info({'EXIT', Pid, Reason}, #rep_state{changes_queue=Pid} = State) ->
     couch_stats:increment_counter([couch_replicator, changes_queue_deaths]),
+    ?LOG_ERROR(#{what => changes_queue_crash, in => replicator, details => Reason}),
     couch_log:error("ChangesQueue process died with reason: ~p", [Reason]),
     {stop, {shutdown, {changes_queue_died, Reason}}, cancel_timers(State)};
 
@@ -297,6 +348,12 @@ handle_info({'EXIT', Pid, normal}, #rep_state{workers = Workers} = State) ->
         Workers ->
             %% Processes might be linked by replicator's auth plugins so
             %% we tolerate them exiting `normal` here and don't crash
+            ?LOG_WARNING(#{
+                what => unknown_process_exit,
+                in => replicator,
+                pid => Pid,
+                reason => normal
+            }),
             LogMsg = "~p: unknown pid exited `normal` ~p",
             couch_log:error(LogMsg, [?MODULE, Pid]),
             {noreply, State#rep_state{workers = Workers}};
@@ -319,6 +376,12 @@ handle_info({'EXIT', Pid, Reason}, #rep_state{workers = Workers} = State) ->
                 {shutdown, _} = Err ->
                     Err;
                 Other ->
+                    ?LOG_ERROR(#{
+                        what => worker_crash,
+                        in => replicator,
+                        pid => Pid,
+                        details => Reason
+                    }),
                     ErrLog = "Worker ~p died with reason: ~p",
                     couch_log:error(ErrLog, [Pid, Reason]),
                     {worker_died, Pid, Other}
@@ -327,6 +390,11 @@ handle_info({'EXIT', Pid, Reason}, #rep_state{workers = Workers} = State) ->
     end;
 
 handle_info({Ref, ready}, St) when is_reference(Ref) ->
+    ?LOG_NOTICE(#{
+        what => spurious_future_ready_message,
+        in => replicator,
+        ref => Ref
+    }),
     LogMsg = "~p : spurious erlfdb future ready message ~p",
     couch_log:notice(LogMsg, [?MODULE, Ref]),
     {noreply, St};
@@ -411,6 +479,12 @@ delayed_init() ->
             {stop, {shutdown, Exit}, {init_error, Stack}};
         _Tag:Error:Stack ->
             Reason = {error, replication_start_error(Error)},
+            ?LOG_ERROR(#{
+                what => job_failure_during_init,
+                job => Job,
+                details => Reason,
+                stacktrace => Stack
+            }),
             ErrMsg = "~p : job ~p failed during startup ~p stack:~p",
             couch_log:error(ErrMsg, [?MODULE, Job, Reason, Stack]),
             reschedule_on_error(undefined, Job, JobData, Reason),
@@ -571,12 +645,25 @@ check_ownership(#{jtx := true} = JTx, Job, JobData) ->
                     fail_job(JTx, Job, JobData, Error),
                     not_owner;
                 {ok, #{}} ->
+                    ?LOG_WARNING(#{
+                        what => duplicate_job_detected,
+                        in => replicator,
+                        jobid => JobId,
+                        other_jobid => OtherJobId,
+                        replication_id => RepId
+                    }),
                     LogMsg = "~p : Job ~p usurping job ~p for replication ~p",
                     couch_log:warning(LogMsg, [?MODULE, JobId, OtherJobId,
                         RepId]),
                     couch_replicator_jobs:update_rep_id(JTx, JobId, RepId),
                     owner;
                 {error, not_found} ->
+                    ?LOG_ERROR(#{
+                        what => orphaned_job_mapping,
+                        in => replicator,
+                        replication_id => RepId,
+                        jobid => OtherJobId
+                    }),
                     LogMsg = "~p : Orphan replication job reference ~p -> ~p",
                     couch_log:error(LogMsg, [?MODULE, RepId, OtherJobId]),
                     couch_replicator_jobs:update_rep_id(JTx, JobId, RepId),
@@ -861,6 +948,11 @@ state_strip_creds(#rep_state{source = Source, target = Target} = State) ->
 
 
 adjust_maxconn(Src = #{<<"http_connections">> := 1}, RepId) ->
+    ?LOG_NOTICE(#{
+        what => minimum_source_connections_override,
+        in => replicator,
+        details => "adjusting minimum source connections to 2"
+    }),
     Msg = "Adjusting minimum number of HTTP source connections to 2 for ~p",
     couch_log:notice(Msg, [RepId]),
     Src#{<<"http_connections">> := 2};
@@ -960,7 +1052,21 @@ init_state(#{} = Job, #{} = JobData) ->
     [SourceLog, TargetLog] = find_and_migrate_logs([Source, Target], Rep,
         BaseId),
 
-    {StartSeq0, History} = compare_replication_logs(SourceLog, TargetLog),
+    {StartSeq0, History, MatchedSessionIds} = compare_replication_logs(SourceLog, TargetLog),
+
+    if not MatchedSessionIds ->
+        ?LOG_NOTICE(#{
+            what => session_history_mismatch,
+            in => replicator,
+            calculated_start_seq => StartSeq0,
+            source => couch_replicator_api_wrap:db_uri(Source),
+            target => couch_replicator_api_wrap:db_uri(Target),
+            replication_id => Id,
+            details => "scanned histories to find common ancestor"
+        });
+    true ->
+        ok
+    end,
 
     #{?REP_STATS := Stats0} = JobData,
     Stats1 = couch_replicator_stats:new(Stats0),
@@ -1043,6 +1149,13 @@ maybe_save_migrated_log(#{?OPTIONS := Options}, Db, #doc{} = Doc, OldId) ->
     case maps:get(<<"use_checkpoints">>, Options) of
         true ->
             update_checkpoint(Db, Doc),
+            ?LOG_NOTICE(#{
+                what => migrated_checkpoint,
+                in => replicator,
+                db => httpdb_strip_creds(Db),
+                old_id => OldId,
+                new_id => Doc#doc.id
+            }),
             Msg = "Migrated replication checkpoint. Db:~p ~p -> ~p",
             couch_log:notice(Msg, [httpdb_strip_creds(Db), OldId, Doc#doc.id]);
         false ->
@@ -1111,6 +1224,13 @@ do_checkpoint(State) ->
             {checkpoint_commit_failure, <<"Failure on target commit: ",
                 (couch_util:to_binary(Reason))/binary>>};
         {SrcInstanceStartTime, TgtInstanceStartTime} ->
+            ?LOG_NOTICE(#{
+                what => checkpoint,
+                in => replicator,
+                source => SourceName,
+                target => TargetName,
+                sequence => NewSeq
+            }),
             couch_log:notice("recording a checkpoint for `~s` -> `~s` at "
                 "source update_seq ~p", [SourceName, TargetName, NewSeq]),
             StartTime = couch_replicator_utils:rfc1123_local(RepStartTime),
@@ -1271,7 +1391,7 @@ compare_replication_logs(SrcDoc, TgtDoc) ->
             OldSeqNum = get_value(<<"source_last_seq">>, RepRecProps,
                 ?LOWEST_SEQ),
             OldHistory = get_value(<<"history">>, RepRecProps, []),
-            {OldSeqNum, OldHistory};
+            {OldSeqNum, OldHistory, true};
         false ->
             SourceHistory = get_value(<<"history">>, RepRecProps, []),
             TargetHistory = get_value(<<"history">>, RepRecPropsTgt, []),
@@ -1279,7 +1399,8 @@ compare_replication_logs(SrcDoc, TgtDoc) ->
                     "Scanning histories to find a common ancestor.", []),
             couch_log:debug("Record on source:~p~nRecord on target:~p~n",
                     [RepRecProps, RepRecPropsTgt]),
-            compare_rep_history(SourceHistory, TargetHistory)
+            {StartSeq, History} = compare_rep_history(SourceHistory, TargetHistory),
+            {StartSeq, History, false}
     end.
 
 
@@ -1426,6 +1547,17 @@ log_replication_start(#rep_state{} = RepState) ->
         _ ->
             "from _replicate endpoint"
     end,
+    ?LOG_NOTICE(#{
+        what => starting_replication,
+        in => replicator,
+        source => Source,
+        target => Target,
+        replication_db => DbName,
+        replication_doc => DocId,
+        session_id => Sid,
+        worker_processes => Workers,
+        worker_batch_size => BatchSize
+    }),
     Msg = "Starting replication ~s (~s -> ~s) ~s worker_procesess:~p"
         " worker_batch_size:~p session_id:~s",
     couch_log:notice(Msg, [Id, Source, Target, From, Workers, BatchSize, Sid]).
@@ -1442,6 +1574,13 @@ check_user_filter(#rep_state{} = State) ->
         {RepId, BaseId} ->
             ok;
         {NewId, NewBaseId} when is_binary(NewId), is_binary(NewBaseId) ->
+            ?LOG_ERROR(#{
+                what => replication_id_updated,
+                in => replicator,
+                old_id => RepId,
+                new_id => NewId,
+                details => "replication job shutting down"
+            }),
             LogMsg = "~p : Replication id was updated ~p -> ~p",
             couch_log:error(LogMsg, [?MODULE, RepId, NewId]),
             reschedule(undefined, Job, JobData),
diff --git a/src/couch_replicator/src/couch_replicator_job_server.erl b/src/couch_replicator/src/couch_replicator_job_server.erl
index a2e90b0..2452a22 100644
--- a/src/couch_replicator/src/couch_replicator_job_server.erl
+++ b/src/couch_replicator/src/couch_replicator_job_server.erl
@@ -38,6 +38,7 @@
 
 
 -include("couch_replicator.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -define(MAX_ACCEPTORS, 2).
@@ -95,6 +96,11 @@ handle_call({accepted, Pid, Normal}, _From, #{} = St) ->
             },
             {reply, ok, spawn_acceptors(St1)};
         false ->
+            ?LOG_ERROR(#{
+                what => unknown_acceptor,
+                in => replicator,
+                pid => Pid
+            }),
             LogMsg = "~p : unknown acceptor processs ~p",
             couch_log:error(LogMsg, [?MODULE, Pid]),
             {stop, {unknown_acceptor_pid, Pid}, St}
@@ -234,6 +240,11 @@ transient_job_cleanup(#{} = St) ->
         case State =:= finished andalso IsTransient andalso IsOld of
             true ->
                 ok = couch_replicator_jobs:remove_job(undefined, JobId),
+                ?LOG_INFO(#{
+                    what => removing_old_job,
+                    in => replicator,
+                    jobid => JobId
+                }),
                 couch_log:info("~p : Removed old job ~p", [?MODULE, JobId]),
                 ok;
             false ->
@@ -301,6 +312,11 @@ wait_jobs_exit(#{} = Jobs, Timeout) ->
             wait_jobs_exit(maps:remove(Pid, Jobs), Timeout)
     after
         Timeout ->
+            ?LOG_ERROR(#{
+                what => unclean_job_termination,
+                in => replicator,
+                job_count => map_size(Jobs)
+            }),
             LogMsg = "~p : ~p jobs didn't terminate cleanly",
             couch_log:error(LogMsg, [?MODULE, map_size(Jobs)]),
             ok
@@ -329,6 +345,12 @@ spawn_acceptors(St) ->
 
 handle_acceptor_exit(#{acceptors := Acceptors} = St, Pid, Reason) ->
     St1 = St#{acceptors := maps:remove(Pid, Acceptors)},
+    ?LOG_ERROR(#{
+        what => acceptor_crash,
+        in => replicator,
+        pid => Pid,
+        details => Reason
+    }),
     LogMsg = "~p : acceptor process ~p exited with ~p",
     couch_log:error(LogMsg, [?MODULE, Pid, Reason]),
     {noreply, spawn_acceptors(St1)}.
@@ -344,6 +366,12 @@ handle_worker_exit(#{workers := Workers} = St, Pid, Reason) ->
         {shutdown, _} ->
             ok;
         _ ->
+            ?LOG_ERROR(#{
+                what => worker_crash,
+                in => replicator,
+                pid => Pid,
+                details => Reason
+            }),
             LogMsg = "~p : replicator job process ~p exited with ~p",
             couch_log:error(LogMsg, [?MODULE, Pid, Reason])
     end,
@@ -351,6 +379,11 @@ handle_worker_exit(#{workers := Workers} = St, Pid, Reason) ->
 
 
 handle_unknown_exit(St, Pid, Reason) ->
+    ?LOG_ERROR(#{
+        what => unknown_process_crash,
+        in => replicator,
+        pid => Pid
+    }),
     LogMsg = "~p : unknown process ~p exited with ~p",
     couch_log:error(LogMsg, [?MODULE, Pid, Reason]),
     {stop, {unknown_pid_exit, Pid}, St}.
diff --git a/src/couch_replicator/src/couch_replicator_parse.erl b/src/couch_replicator/src/couch_replicator_parse.erl
index 5b3f3f3..ac25bee 100644
--- a/src/couch_replicator/src/couch_replicator_parse.erl
+++ b/src/couch_replicator/src/couch_replicator_parse.erl
@@ -23,6 +23,7 @@
 
 -include_lib("ibrowse/include/ibrowse.hrl").
 -include("couch_replicator.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -define(DEFAULT_SOCK_OPTS, "[{keepalive, true}, {nodelay, false}]").
@@ -60,10 +61,23 @@ parse_rep_doc(RepDoc) ->
         parse_rep(RepDoc, null)
     catch
         throw:{error, Reason}:Stack ->
+            ?LOG_ERROR(#{
+                what => replication_doc_parse_error,
+                in => replicator,
+                details => Reason,
+                stacktrace => Stack
+            }),
             LogErr1 = "~p parse_rep_doc fail ~p ~p",
             couch_log:error(LogErr1, [?MODULE, Reason, Stack]),
             throw({bad_rep_doc, Reason});
         Tag:Err:Stack ->
+            ?LOG_ERROR(#{
+                what => replication_doc_parse_error,
+                in => replicator,
+                tag => Tag,
+                details => Err,
+                stacktrace => Stack
+            }),
             LogErr2 = "~p parse_rep_doc fail ~p:~p ~p",
             couch_log:error(LogErr2, [?MODULE, Tag, Err, Stack]),
             throw({bad_rep_doc, couch_util:to_binary({Tag, Err})})
@@ -82,10 +96,23 @@ parse_transient_rep(#{} = Body, UserName) ->
         parse_rep(Body, UserName)
     catch
         throw:{error, Reason}:Stack ->
+            ?LOG_ERROR(#{
+                what => transient_replication_parse_error,
+                in => replicator,
+                details => Reason,
+                stacktrace => Stack
+            }),
             LogErr1 = "~p parse_transient_rep fail ~p ~p",
             couch_log:error(LogErr1, [?MODULE, Reason, Stack]),
             throw({bad_request, Reason});
         Tag:Err:Stack ->
+            ?LOG_ERROR(#{
+                what => transient_replication_parse_error,
+                in => replicator,
+                tag => Tag,
+                details => Err,
+                stacktrace => Stack
+            }),
             LogErr2 = "~p parse_transient_rep fail ~p ~p",
             couch_log:error(LogErr2, [?MODULE, Tag, Err, Stack]),
             throw({bad_request, couch_util:to_binary({Tag, Err})})
diff --git a/src/couch_replicator/src/couch_replicator_worker.erl b/src/couch_replicator/src/couch_replicator_worker.erl
index 4cd984c..d236b6b 100644
--- a/src/couch_replicator/src/couch_replicator_worker.erl
+++ b/src/couch_replicator/src/couch_replicator_worker.erl
@@ -25,6 +25,7 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_replicator/include/couch_replicator_api_wrap.hrl").
 -include("couch_replicator.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 % TODO: maybe make both buffer max sizes configurable
 -define(DOC_BUFFER_BYTE_SIZE, 512 * 1024).   % for remote targets
@@ -225,6 +226,11 @@ queue_fetch_loop(Source, Target, Parent, Cp, ChangesManager) ->
         {ok, Stats} = gen_server:call(Parent, flush, infinity),
         ok = gen_server:call(Cp, {report_seq_done, ReportSeq, Stats}, infinity),
         erlang:put(last_stats_report, os:timestamp()),
+        ?LOG_DEBUG(#{
+            what => worker_progress_report,
+            in => replicator,
+            seq => ReportSeq
+        }),
         couch_log:debug("Worker reported completion of seq ~p", [ReportSeq]),
         queue_fetch_loop(Source, Target, Parent, Cp, ChangesManager)
     end.
@@ -265,6 +271,14 @@ fetch_doc(Source, {Id, Revs, PAs}, DocHandler, Acc) ->
             [Id, couch_doc:revs_to_strs(Revs)]),
         WaitMSec = config:get_integer("replicator", "missing_doc_retry_msec",
             ?MISSING_DOC_RETRY_MSEC),
+        ?LOG_ERROR(#{
+            what => missing_document,
+            in => replicator,
+            source => couch_replicator_api_wrap:db_uri(Source),
+            docid => Id,
+            revisions => couch_doc:revs_to_strs(Revs),
+            retry_delay => WaitMSec / 1000
+        }),
         timer:sleep(WaitMSec),
         couch_replicator_api_wrap:open_doc_revs(Source, Id, Revs, [latest], DocHandler, Acc);
     throw:{missing_stub, _} ->
@@ -273,6 +287,14 @@ fetch_doc(Source, {Id, Revs, PAs}, DocHandler, Acc) ->
             [Id, couch_doc:revs_to_strs(Revs)]),
         WaitMSec = config:get_integer("replicator", "missing_doc_retry_msec",
             ?MISSING_DOC_RETRY_MSEC),
+        ?LOG_ERROR(#{
+            what => missing_attachment_stub,
+            in => replicator,
+            source => couch_replicator_api_wrap:db_uri(Source),
+            docid => Id,
+            revisions => couch_doc:revs_to_strs(Revs),
+            retry_delay => WaitMSec / 1000
+        }),
         timer:sleep(WaitMSec),
         couch_replicator_api_wrap:open_doc_revs(Source, Id, Revs, [latest], DocHandler, Acc)
     end.
@@ -282,6 +304,7 @@ remote_doc_handler({ok, #doc{id = <<?DESIGN_DOC_PREFIX, _/binary>>} = Doc},
         Acc) ->
     % Flush design docs in their own PUT requests to correctly process
     % authorization failures for design doc updates.
+    ?LOG_DEBUG(#{what => flush_ddoc, in => replicator}),
     couch_log:debug("Worker flushing design doc", []),
     doc_handler_flush_doc(Doc, Acc);
 remote_doc_handler({ok, #doc{atts = [_ | _]} = Doc}, Acc) ->
@@ -289,6 +312,7 @@ remote_doc_handler({ok, #doc{atts = [_ | _]} = Doc}, Acc) ->
     % source. The data property of each attachment is a function that starts
     % streaming the attachment data from the remote source, therefore it's
     % convenient to call it ASAP to avoid ibrowse inactivity timeouts.
+    ?LOG_DEBUG(#{what => flush_doc_with_attachments, in => replicator}),
     couch_log:debug("Worker flushing doc with attachments", []),
     doc_handler_flush_doc(Doc, Acc);
 remote_doc_handler({ok, #doc{atts = []} = Doc}, {Parent, _} = Acc) ->
@@ -314,6 +338,11 @@ doc_handler_flush_doc(#doc{} = Doc, {Parent, Target} = Acc) ->
 spawn_writer(Target, #batch{docs = DocList, size = Size}) ->
     case {Target, Size > 0} of
     {#httpdb{}, true} ->
+        ?LOG_DEBUG(#{
+            what => flush_doc_batch,
+            in => replicator,
+            batch_size => Size
+        }),
         couch_log:debug("Worker flushing doc batch of size ~p bytes", [Size]);
     _ ->
         ok
@@ -354,6 +383,11 @@ maybe_flush_docs(#httpdb{} = Target, Batch, Doc) ->
     JsonDoc = ?JSON_ENCODE(couch_doc:to_json_obj(Doc, [revs, attachments])),
     case SizeAcc + iolist_size(JsonDoc) of
     SizeAcc2 when SizeAcc2 > ?DOC_BUFFER_BYTE_SIZE ->
+        ?LOG_DEBUG(#{
+            what => flush_doc_batch,
+            in => replicator,
+            batch_size => SizeAcc2
+        }),
         couch_log:debug("Worker flushing doc batch of size ~p bytes", [SizeAcc2]),
         Stats = flush_docs(Target, [JsonDoc | DocAcc]),
         {#batch{}, Stats};
@@ -371,12 +405,27 @@ flush_docs(Target, DocList) ->
     handle_flush_docs_result(FlushResult, Target, DocList).
 
 
-handle_flush_docs_result({error, request_body_too_large}, _Target, [Doc]) ->
+handle_flush_docs_result({error, request_body_too_large}, Target, [Doc]) ->
+    ?LOG_ERROR(#{
+        what => doc_write_failure,
+        in => replicator,
+        target => couch_replicator_api_wrap:db_uri(Target),
+        reason => request_body_too_large,
+        docid => extract_value(<<"_id">>, Doc)
+    }),
     couch_log:error("Replicator: failed to write doc ~p. Too large", [Doc]),
     couch_replicator_stats:new([{doc_write_failures, 1}]);
 handle_flush_docs_result({error, request_body_too_large}, Target, DocList) ->
     Len = length(DocList),
     {DocList1, DocList2} = lists:split(Len div 2, DocList),
+    ?LOG_NOTICE(#{
+        what => split_large_batch,
+        in => replicator,
+        target => couch_replicator_api_wrap:db_uri(Target),
+        reason => request_body_too_large,
+        original_batch_size => Len,
+        details => "splitting into two smaller batches and retrying"
+    }),
     couch_log:notice("Replicator: couldn't write batch of size ~p to ~p because"
         " request body is too large. Splitting batch into 2 separate batches of"
         " sizes ~p and ~p", [Len, couch_replicator_api_wrap:db_uri(Target),
@@ -388,6 +437,15 @@ handle_flush_docs_result({ok, Errors}, Target, DocList) ->
     DbUri = couch_replicator_api_wrap:db_uri(Target),
     lists:foreach(
         fun({Props}) ->
+            ?LOG_ERROR(#{
+                what => doc_write_failure,
+                in => replicator,
+                target => couch_replicator_api_wrap:db_uri(Target),
+                docid => get_value(id, Props, undefined),
+                revision => get_value(rev, Props, undefined),
+                error => get_value(error, Props, undefined),
+                details => get_value(reason, Props, undefined)
+            }),
             couch_log:error("Replicator: couldn't write document `~s`, revision"
                 " `~s`, to target database `~s`. Error: `~s`, reason: `~s`.", [
                 get_value(id, Props, ""), get_value(rev, Props, ""), DbUri,
@@ -400,12 +458,29 @@ handle_flush_docs_result({ok, Errors}, Target, DocList) ->
 handle_flush_docs_result({error, {bulk_docs_failed, _, _} = Err}, _, _) ->
     exit(Err).
 
+extract_value(Prop, Json) when is_binary(Json) ->
+    try
+        {Props} = ?JSON_DECODE(Json),
+        get_value(Prop, Props, undefined)
+    catch _:_ ->
+        undefined
+    end;
+extract_value(_, _) ->
+    undefined.
 
 flush_doc(Target, #doc{id = Id, revs = {Pos, [RevId | _]}} = Doc) ->
     try couch_replicator_api_wrap:update_doc(Target, Doc, [], replicated_changes) of
     {ok, _} ->
         ok;
     Error ->
+        ?LOG_ERROR(#{
+            what => doc_write_failure,
+            in => replicator,
+            target => couch_replicator_api_wrap:db_uri(Target),
+            docid => Id,
+            revision => couch_doc:rev_to_str({Pos, RevId}),
+            details => Error
+        }),
         couch_log:error("Replicator: error writing document `~s` to `~s`: ~s",
             [Id, couch_replicator_api_wrap:db_uri(Target), couch_util:to_binary(Error)]),
         Error
@@ -413,12 +488,29 @@ flush_doc(Target, #doc{id = Id, revs = {Pos, [RevId | _]}} = Doc) ->
     throw:{missing_stub, _} = MissingStub ->
         throw(MissingStub);
     throw:{Error, Reason} ->
+        ?LOG_ERROR(#{
+            what => doc_write_failure,
+            in => replicator,
+            target => couch_replicator_api_wrap:db_uri(Target),
+            docid => Id,
+            revision => couch_doc:rev_to_str({Pos, RevId}),
+            error => Error,
+            details => Reason
+        }),
         couch_log:error("Replicator: couldn't write document `~s`, revision `~s`,"
             " to target database `~s`. Error: `~s`, reason: `~s`.",
             [Id, couch_doc:rev_to_str({Pos, RevId}),
                 couch_replicator_api_wrap:db_uri(Target), to_binary(Error), to_binary(Reason)]),
         {error, Error};
     throw:Err ->
+        ?LOG_ERROR(#{
+            what => doc_write_failure,
+            in => replicator,
+            target => couch_replicator_api_wrap:db_uri(Target),
+            docid => Id,
+            revision => couch_doc:rev_to_str({Pos, RevId}),
+            details => Err
+        }),
         couch_log:error("Replicator: couldn't write document `~s`, revision `~s`,"
             " to target database `~s`. Error: `~s`.",
             [Id, couch_doc:rev_to_str({Pos, RevId}),
diff --git a/src/couch_views/src/couch_views_indexer.erl b/src/couch_views/src/couch_views_indexer.erl
index eed3f54..7f0e2d5 100644
--- a/src/couch_views/src/couch_views_indexer.erl
+++ b/src/couch_views/src/couch_views_indexer.erl
@@ -31,6 +31,7 @@
 -include("couch_views.hrl").
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("fabric/include/fabric2.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -define(KEY_SIZE_LIMIT, 8000).
@@ -122,6 +123,14 @@ init() ->
         error:database_does_not_exist ->
             fail_job(Job, Data, db_deleted, "Database was deleted");
         Error:Reason:Stack ->
+            ?LOG_ERROR(#{
+                what => view_update_failure,
+                db => DbName,
+                ddoc => DDocId,
+                tag => Error,
+                details => Reason,
+                stacktrace => Stack
+            }),
             Fmt = "Error building view for ddoc ~s in ~s: ~p:~p ~p",
             couch_log:error(Fmt, [DbName, DDocId, Error, Reason, Stack]),
 
@@ -592,6 +601,12 @@ check_kv_size_limit(Mrst, Doc, KeyLimit, ValLimit) ->
         Doc
     catch throw:{size_error, Type} ->
         #{id := DocId} = Doc,
+        ?LOG_ERROR(#{
+            what => lists:concat(["oversized_", Type]),
+            db => DbName,
+            docid => DocId,
+            index => IdxName
+        }),
         Fmt = "View ~s size error for docid `~s`, excluded from indexing "
             "in db `~s` for design doc `~s`",
         couch_log:error(Fmt, [Type, DocId, DbName, IdxName]),
@@ -662,6 +677,7 @@ report_progress(State, UpdateType) ->
                 {ok, Job2} ->
                     State#{job := Job2};
                 {error, halt} ->
+                    ?LOG_ERROR(#{what => job_halted, job => Job1}),
                     couch_log:error("~s job halted :: ~w", [?MODULE, Job1]),
                     exit(normal)
             end;
@@ -670,6 +686,7 @@ report_progress(State, UpdateType) ->
                 ok ->
                     State;
                 {error, halt} ->
+                    ?LOG_ERROR(#{what => job_halted, job => Job1}),
                     couch_log:error("~s job halted :: ~w", [?MODULE, Job1]),
                     exit(normal)
             end
diff --git a/src/couch_views/src/couch_views_server.erl b/src/couch_views/src/couch_views_server.erl
index 71a4abb..e94eaf1 100644
--- a/src/couch_views/src/couch_views_server.erl
+++ b/src/couch_views/src/couch_views_server.erl
@@ -15,6 +15,7 @@
 
 -behaviour(gen_server).
 
+-include_lib("kernel/include/logger.hrl").
 
 -export([
     start_link/0
@@ -75,6 +76,7 @@ handle_call({accepted, Pid}, _From, St) ->
             },
             {reply, ok, spawn_acceptors(St1)};
         false ->
+            ?LOG_ERROR(#{what => unknown_acceptor, pid => Pid}),
             LogMsg = "~p : unknown acceptor processs ~p",
             couch_log:error(LogMsg, [?MODULE, Pid]),
             {stop, {unknown_acceptor_pid, Pid}, St}
@@ -127,6 +129,7 @@ format_status(_Opt, [_PDict, State]) ->
 
 handle_acceptor_exit(#{acceptors := Acceptors} = St, Pid, Reason) ->
     St1 = St#{acceptors := maps:remove(Pid, Acceptors)},
+    ?LOG_ERROR(#{what => acceptor_crash, pid => Pid, reason => Reason}),
     LogMsg = "~p : acceptor process ~p exited with ~p",
     couch_log:error(LogMsg, [?MODULE, Pid, Reason]),
     {noreply, spawn_acceptors(St1)}.
@@ -138,12 +141,14 @@ handle_worker_exit(#{workers := Workers} = St, Pid, normal) ->
 
 handle_worker_exit(#{workers := Workers} = St, Pid, Reason) ->
     St1 = St#{workers := maps:remove(Pid, Workers)},
+    ?LOG_ERROR(#{what => indexer_crash, pid => Pid, reason => Reason}),
     LogMsg = "~p : indexer process ~p exited with ~p",
     couch_log:error(LogMsg, [?MODULE, Pid, Reason]),
     {noreply, spawn_acceptors(St1)}.
 
 
 handle_unknown_exit(St, Pid, Reason) ->
+    ?LOG_ERROR(#{what => unknown_process_crash, pid => Pid, reason => Reason}),
     LogMsg = "~p : unknown process ~p exited with ~p",
     couch_log:error(LogMsg, [?MODULE, Pid, Reason]),
     {stop, {unknown_pid_exit, Pid}, St}.
diff --git a/src/couch_views/src/couch_views_sup.erl b/src/couch_views/src/couch_views_sup.erl
index 9453189..ee32d4e 100644
--- a/src/couch_views/src/couch_views_sup.erl
+++ b/src/couch_views/src/couch_views_sup.erl
@@ -16,6 +16,7 @@
 
 -behaviour(supervisor).
 
+-include_lib("kernel/include/logger.hrl").
 
 -export([
     start_link/0
@@ -46,6 +47,7 @@ init(normal) ->
     {ok, {flags(), Children}};
 
 init(builds_disabled) ->
+    ?LOG_NOTICE(#{what => view_indexing_disabled}),
     couch_log:notice("~p : view_indexing disabled", [?MODULE]),
     couch_views_jobs:set_timeout(),
     {ok, {flags(), []}}.
diff --git a/src/couch_views/src/couch_views_updater.erl b/src/couch_views/src/couch_views_updater.erl
index c7d3146..f88c5a2 100644
--- a/src/couch_views/src/couch_views_updater.erl
+++ b/src/couch_views/src/couch_views_updater.erl
@@ -18,6 +18,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_views/include/couch_views.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 % If the doc revision doesn't not match the NewRevId passed here we can ignore
 % the document since it is then a conflict document and it doesn't need
@@ -33,11 +34,25 @@ index(Db, #doc{id = Id, revs = Revs} = Doc, _NewWinner, _OldWinner, NewRevId,
     catch
         error:{erlfdb_error, ErrCode}:Stack when is_integer(ErrCode) ->
             DbName = fabric2_db:name(Db),
+            ?LOG_ERROR(#{
+                what => mango_index_update,
+                status => erlfdb_error,
+                details => ErrCode,
+                db => DbName,
+                docid => Id
+            }),
             couch_log:error("Mango index erlfdb error Db ~s Doc ~p ~p",
                 [DbName, Id, ErrCode]),
             erlang:raise(error, {erlfdb_error, ErrCode}, Stack);
         Error:Reason ->
             DbName = fabric2_db:name(Db),
+            ?LOG_ERROR(#{
+                what => mango_index_update,
+                status => Error,
+                details => Reason,
+                db => DbName,
+                docid => Id
+            }),
             couch_log:error("Mango index error for Db ~s Doc ~p ~p ~p",
                 [DbName, Id, Error, Reason])
     end.
diff --git a/src/couch_views/src/couch_views_util.erl b/src/couch_views/src/couch_views_util.erl
index 287d4ba..63f5daa 100644
--- a/src/couch_views/src/couch_views_util.erl
+++ b/src/couch_views/src/couch_views_util.erl
@@ -30,6 +30,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include("couch_views.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 ddoc_to_mrst(DbName, #doc{id=Id, body={Fields}}) ->
@@ -56,6 +57,12 @@ ddoc_to_mrst(DbName, #doc{id=Id, body={Fields}}) ->
                 DictBySrcAcc
         end;
         ({Name, Else}, DictBySrcAcc) ->
+            ?LOG_ERROR(#{
+                what => invalid_view_definition,
+                db => DbName,
+                ddoc => Id,
+                view => Name
+            }),
             couch_log:error("design_doc_to_view_group ~s views ~p",
                 [Name, Else]),
             DictBySrcAcc
diff --git a/src/ctrace/src/ctrace.erl b/src/ctrace/src/ctrace.erl
index a890bde..2821352 100644
--- a/src/ctrace/src/ctrace.erl
+++ b/src/ctrace/src/ctrace.erl
@@ -44,6 +44,7 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("passage/include/opentracing.hrl").
 -include("ctrace.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -type operation()
diff --git a/src/ctrace/src/ctrace_config.erl b/src/ctrace/src/ctrace_config.erl
index c63c77f..e9141d2 100644
--- a/src/ctrace/src/ctrace_config.erl
+++ b/src/ctrace/src/ctrace_config.erl
@@ -29,6 +29,7 @@
 ]).
 
 -include("ctrace.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -spec is_enabled() -> boolean().
@@ -132,10 +133,12 @@ http_client(Endpoint, Method, Headers, Body, _ReporterOptions) ->
 
 compile_filter(OperationId, FilterDef) ->
     try
+        ?LOG_INFO(#{what => compile_filter, id => OperationId}),
         couch_log:info("Compiling filter : ~s", [OperationId]),
         ctrace_dsl:compile(OperationId, FilterDef),
         true
     catch throw:{error, Reason} ->
+        ?LOG_ERROR(#{what => compile_filter, id => OperationId, details => Reason}),
         couch_log:error("Cannot compile ~s :: ~s~n", [OperationId, Reason]),
         false
     end.
diff --git a/src/ctrace/test/ctrace_config_test.erl b/src/ctrace/test/ctrace_config_test.erl
index 0827013..bc108b2 100644
--- a/src/ctrace/test/ctrace_config_test.erl
+++ b/src/ctrace/test/ctrace_config_test.erl
@@ -14,6 +14,7 @@
 
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("ctrace/src/ctrace.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -define(TDEF(A), {atom_to_list(A), fun A/0}).
@@ -79,6 +80,7 @@ ensure_all_supported() ->
 
 
 handle_all_syntax_error_supported() ->
+    ?LOG_ERROR(#{what => xkcd, event => test_start}),
     couch_log:error("XKCD: TEST START", []),
     config:delete("tracing.filters", "all", false),
     test_util:wait_value(fun() ->
@@ -96,6 +98,7 @@ handle_all_syntax_error_supported() ->
     % then we default to not generating traces
     ?assertEqual(false, ctrace:match(bam, #{gee => whiz})),
 
+    ?LOG_ERROR(#{what => xkcd, event => test_end}),
     couch_log:error("XKCD: TEST END", []),
     config:delete("tracing.filters", "all", false).
 
diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl
index 0074865..91baa27 100644
--- a/src/fabric/src/fabric2_db.erl
+++ b/src/fabric/src/fabric2_db.erl
@@ -139,6 +139,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include("fabric2.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 % Default max database name length is based on CouchDb < 4.x compatibility. See
@@ -850,6 +851,7 @@ validate_docid(Id) when is_binary(Id) ->
     _Else -> ok
     end;
 validate_docid(Id) ->
+    ?LOG_DEBUG(#{what => illegal_docid, docid => Id}),
     couch_log:debug("Document id is not a string: ~p", [Id]),
     throw({illegal_docid, <<"Document id must be a string">>}).
 
diff --git a/src/fabric/src/fabric2_db_expiration.erl b/src/fabric/src/fabric2_db_expiration.erl
index b438591..b8a063c 100644
--- a/src/fabric/src/fabric2_db_expiration.erl
+++ b/src/fabric/src/fabric2_db_expiration.erl
@@ -34,6 +34,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("fabric/include/fabric2.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(JOB_TYPE, <<"db_expiration">>).
 -define(JOB_ID, <<"db_expiration_job">>).
@@ -81,7 +82,9 @@ handle_info(timeout, #st{job = undefined} = St) ->
 handle_info({'EXIT', Pid, Exit}, #st{job = Pid} = St) ->
     case Exit of
         normal -> ok;
-        Error -> couch_log:error("~p : job error ~p", [?MODULE, Error])
+        Error ->
+            ?LOG_ERROR(#{what => job_error, details => Error}),
+            couch_log:error("~p : job error ~p", [?MODULE, Error])
     end,
     NewPid = spawn_link(?MODULE, cleanup, [is_enabled()]),
     {noreply, St#st{job = NewPid}};
@@ -132,6 +135,11 @@ cleanup(true) ->
                 ok = resubmit_job(Job1, Data1, schedule_sec())
             catch
                 _Tag:Error:Stack ->
+                    ?LOG_ERROR(#{
+                        what => process_expirations_error,
+                        job => Job,
+                        details => Error
+                    }),
                     couch_log:error("~p : processing error ~p ~p ~p",
                         [?MODULE, Job, Error, Stack]),
                     ok = resubmit_job(Job, Data, ?ERROR_RESCHEDULE_SEC),
@@ -179,6 +187,11 @@ process_row(DbInfo) ->
     Since = Now - Retention,
     case Since >= timestamp_to_sec(TimeStamp)  of
         true ->
+            ?LOG_NOTICE(#{
+                what => expire_db,
+                db => DbName,
+                deleted_at => TimeStamp
+            }),
             couch_log:notice("Permanently deleting ~s database with"
                 " timestamp ~s", [DbName, TimeStamp]),
             ok = fabric2_db:delete(DbName, [{deleted_at, TimeStamp}]);
diff --git a/src/fabric/src/fabric2_index.erl b/src/fabric/src/fabric2_index.erl
index 037f0f5..8d52e8b 100644
--- a/src/fabric/src/fabric2_index.erl
+++ b/src/fabric/src/fabric2_index.erl
@@ -34,6 +34,7 @@
 
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 -callback build_indices(Db :: map(), DDocs :: list(#doc{})) ->
@@ -69,6 +70,13 @@ cleanup(Db) ->
             ok;
         Tag:Reason:Stack ->
             DbName = fabric2_db:name(Db),
+            ?LOG_ERROR(#{
+                what => index_cleanup_failure,
+                db => DbName,
+                tag => Tag,
+                details => Reason,
+                stacktrace => Stack
+            }),
             LogMsg = "~p failed to cleanup indices for `~s` ~p:~p ~p",
             couch_log:error(LogMsg, [?MODULE, DbName, Tag, Reason, Stack])
     end.
@@ -168,6 +176,13 @@ process_updates_iter([Db | Rest], Cont) ->
         error:database_does_not_exist ->
             ok;
         Tag:Reason:Stack ->
+            ?LOG_ERROR(#{
+                what => index_build_failure,
+                db => Db,
+                tag => Tag,
+                details => Reason,
+                stacktrace => Stack
+            }),
             LogMsg = "~p failed to build indices for `~s` ~p:~p ~p",
             couch_log:error(LogMsg, [?MODULE, Db, Tag, Reason, Stack])
     end,
diff --git a/src/fabric/src/fabric2_server.erl b/src/fabric/src/fabric2_server.erl
index e427f20..c68ff88 100644
--- a/src/fabric/src/fabric2_server.erl
+++ b/src/fabric/src/fabric2_server.erl
@@ -43,6 +43,7 @@
 
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("kernel/include/file.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(CLUSTER_FILE_MACOS, "/usr/local/etc/foundationdb/fdb.cluster").
 -define(CLUSTER_FILE_LINUX, "/etc/foundationdb/fdb.cluster").
@@ -254,14 +255,25 @@ find_cluster_file([{custom, undefined} | Rest]) ->
     find_cluster_file(Rest);
 
 find_cluster_file([{Type, Location} | Rest]) ->
+    Msg = #{
+        in => fdb_connection_setup,
+        configuration_type => Type,
+        cluster_file => Location
+    },
     case file:read_file_info(Location, [posix]) of
         {ok, #file_info{access = read_write}} ->
+            ?LOG_INFO(maps:merge(Msg, #{status => ok})),
             couch_log:info(
                 "Using ~s FDB cluster file: ~s",
                 [Type, Location]
             ),
             {ok, Location};
         {ok, #file_info{access = read}} ->
+            ?LOG_WARNING(maps:merge(Msg, #{
+                status => read_only_file,
+                details => "If coordinators are changed without updating this "
+                    "file CouchDB may be unable to connect to the FDB cluster!"
+            })),
             couch_log:warning(
                 "Using read-only ~s FDB cluster file: ~s -- if coordinators "
                 "are changed without updating this file CouchDB may be unable "
@@ -270,24 +282,31 @@ find_cluster_file([{Type, Location} | Rest]) ->
             ),
             {ok, Location};
         {ok, _} ->
+            ?LOG_ERROR(maps:merge(Msg, #{
+                status => permissions_error,
+                details => "CouchDB needs read/write access to FDB cluster file"
+            })),
             couch_log:error(
                 "CouchDB needs read/write access to FDB cluster file: ~s",
                 [Location]
             ),
             {error, cluster_file_permissions};
         {error, Reason} when Type =:= custom ->
+            ?LOG_ERROR(maps:merge(Msg, #{status => Reason})),
             couch_log:error(
                 "Encountered ~p error looking for FDB cluster file: ~s",
                 [Reason, Location]
             ),
             {error, Reason};
         {error, enoent} when Type =:= default ->
+            ?LOG_INFO(maps:merge(Msg, #{status => enoent})),
             couch_log:info(
                 "No FDB cluster file found at ~s",
                 [Location]
             ),
             find_cluster_file(Rest);
         {error, Reason} when Type =:= default ->
+            ?LOG_WARNING(maps:merge(Msg, #{status => Reason})),
             couch_log:warning(
                 "Encountered ~p error looking for FDB cluster file: ~s",
                 [Reason, Location]
@@ -315,6 +334,11 @@ apply_tx_option(Db, Option, Val, integer) ->
         set_option(Db, Option, list_to_integer(Val))
     catch
         error:badarg ->
+            ?LOG_ERROR(#{
+                what => invalid_transaction_option_value,
+                option => Option,
+                value => Val
+            }),
             Msg = "~p : Invalid integer tx option ~p = ~p",
             couch_log:error(Msg, [?MODULE, Option, Val])
     end;
@@ -325,6 +349,12 @@ apply_tx_option(Db, Option, Val, binary) ->
         true ->
             set_option(Db, Option, BinVal);
         false ->
+            ?LOG_ERROR(#{
+                what => invalid_transaction_option_value,
+                option => Option,
+                value => Val,
+                details => "string transaction option must be less than 16 bytes"
+            }),
             Msg = "~p : String tx option ~p is larger than 16 bytes",
             couch_log:error(Msg, [?MODULE, Option])
     end.
@@ -337,6 +367,11 @@ set_option(Db, Option, Val) ->
         % This could happen if the option is not supported by erlfdb or
         % fdbsever.
         error:badarg ->
+            ?LOG_ERROR(#{
+                what => transaction_option_error,
+                option => Option,
+                value => Val
+            }),
             Msg = "~p : Could not set fdb tx option ~p = ~p",
             couch_log:error(Msg, [?MODULE, Option, Val])
     end.
diff --git a/src/fabric/src/fabric2_users_db.erl b/src/fabric/src/fabric2_users_db.erl
index 9a8a462..fdc787a 100644
--- a/src/fabric/src/fabric2_users_db.erl
+++ b/src/fabric/src/fabric2_users_db.erl
@@ -19,6 +19,7 @@
 ]).
 
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 -define(NAME, <<"name">>).
 -define(PASSWORD, <<"password">>).
@@ -94,6 +95,13 @@ save_doc(#doc{body={Body}} = Doc) ->
         Body4 = proplists:delete(?PASSWORD, Body3),
         Doc#doc{body={Body4}};
     {_ClearPassword, Scheme} ->
+        ?LOG_ERROR(#{
+            what => invalid_config_setting,
+            section => couch_httpd_auth,
+            key => password_scheme,
+            value => Scheme,
+            details => "password_scheme must one of (simple, pbkdf2)"
+        }),
         couch_log:error("[couch_httpd_auth] password_scheme value of '~p' is invalid.", [Scheme]),
         throw({forbidden, "Server cannot hash passwords at this time."})
     end.
diff --git a/src/mango/src/mango_cursor_view.erl b/src/mango/src/mango_cursor_view.erl
index 992e9cf..4a22e15 100644
--- a/src/mango/src/mango_cursor_view.erl
+++ b/src/mango/src/mango_cursor_view.erl
@@ -30,6 +30,7 @@
 -include_lib("couch_views/include/couch_views.hrl").
 -include("mango_cursor.hrl").
 -include("mango_idx_view.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 create(Db, Indexes, Selector, Opts) ->
@@ -241,6 +242,7 @@ handle_message({row, Props}, Cursor) ->
             },
             {ok, Cursor1};
         Error ->
+            ?LOG_ERROR(#{what => load_doc_failure, details => Error}),
             couch_log:error("~s :: Error loading doc: ~p", [?MODULE, Error]),
             {ok, Cursor}
     end;
diff --git a/src/mango/src/mango_idx_view.erl b/src/mango/src/mango_idx_view.erl
index a73d82a..35b741a 100644
--- a/src/mango/src/mango_idx_view.erl
+++ b/src/mango/src/mango_idx_view.erl
@@ -35,6 +35,7 @@
 -include("mango.hrl").
 -include("mango_idx.hrl").
 -include("mango_idx_view.hrl").
+-include_lib("kernel/include/logger.hrl").
 
 
 validate_new(#idx{}=Idx, _Db) ->
@@ -254,6 +255,12 @@ validate_ddoc(VProps) ->
         Opts = lists:keydelete(<<"sort">>, 1, Opts0),
         {Def, Opts}
     catch Error:Reason ->
+        ?LOG_ERROR(#{
+            what => invalid_index_definition,
+            tag => Error,
+            details => Reason,
+            index => VProps
+        }),
         couch_log:error("Invalid Index Def ~p. Error: ~p, Reason: ~p",
             [VProps, Error, Reason]),
         invalid_view

[couchdb] 01/03: Drop support for Erlang < 21

Posted by ko...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kocolosk pushed a commit to branch new-logger
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit b41ffa20c5dbb3f139162721c83262f0b7ce1275
Author: Adam Kocoloski <ko...@apache.org>
AuthorDate: Mon Apr 19 13:23:34 2021 -0400

    Drop support for Erlang < 21
    
    The new logger only works in Erlang 21+, so we can start simplifying
    the codebase by removing the macro that provides support for retrieving
    stack traces the old way.
---
 rebar.config.script                                |  2 +-
 src/chttpd/src/chttpd.erl                          |  8 ++++----
 src/chttpd/src/chttpd_handlers.erl                 |  2 +-
 src/chttpd/src/chttpd_stats.erl                    |  4 +---
 src/couch/include/couch_db.hrl                     | 24 ----------------------
 src/couch/src/couch_proc_manager.erl               |  2 +-
 src/couch_js/src/couch_js_proc_manager.erl         |  2 +-
 src/couch_replicator/src/couch_replicator_job.erl  | 18 +++++++---------
 .../src/couch_replicator_parse.erl                 |  9 ++++----
 src/couch_views/src/couch_views_indexer.erl        |  2 +-
 src/couch_views/src/couch_views_updater.erl        |  2 +-
 src/ctrace/src/ctrace.erl                          |  2 +-
 src/fabric/src/fabric2_db_expiration.erl           |  2 +-
 src/fabric/src/fabric2_index.erl                   |  4 ++--
 src/fabric/src/fabric2_util.erl                    |  2 +-
 src/mango/src/mango_httpd.erl                      |  2 +-
 16 files changed, 28 insertions(+), 59 deletions(-)

diff --git a/rebar.config.script b/rebar.config.script
index 6dafa8f..883b803 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -191,7 +191,7 @@ ErlOpts = case os:getenv("ERL_OPTS") of
 end.
 
 AddConfig = [
-    {require_otp_vsn, "20|21|22|23"},
+    {require_otp_vsn, "21|22|23"},
     {deps_dir, "src"},
     {deps, lists:map(MakeDep, DepDescs ++ OptionalDeps)},
     {sub_dirs, SubDirs},
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index 135c4ec..6741ca3 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -278,7 +278,7 @@ before_request(HttpReq) ->
         {ok, HttpReq1} = chttpd_plugin:before_request(HttpReq),
         chttpd_stats:init(HttpReq1),
         {ok, HttpReq1}
-    catch ?STACKTRACE(Tag, Error, Stack)
+    catch Tag:Error:Stack ->
         {error, catch_error(HttpReq, Tag, Error, Stack)}
     end.
 
@@ -286,7 +286,7 @@ after_request(HttpReq, HttpResp0) ->
     {ok, HttpResp1} =
         try
             chttpd_plugin:after_request(HttpReq, HttpResp0)
-        catch ?STACKTRACE(_Tag, Error, Stack)
+        catch _Tag:Error:Stack ->
             send_error(HttpReq, {Error, nil, Stack}),
             {ok, HttpResp0#httpd_resp{status = aborted}}
         end,
@@ -319,7 +319,7 @@ process_request(#httpd{mochi_req = MochiReq} = HttpReq) ->
         Response ->
             {HttpReq, Response}
         end
-    catch ?STACKTRACE(Tag, Error, Stack)
+    catch Tag:Error:Stack ->
         {HttpReq, catch_error(HttpReq, Tag, Error, Stack)}
     end.
 
@@ -332,7 +332,7 @@ handle_req_after_auth(HandlerKey, HttpReq) ->
         AuthorizedReq = chttpd_auth:authorize(possibly_hack(HttpReq),
             fun chttpd_auth_request:authorize_request/1),
         {AuthorizedReq, HandlerFun(AuthorizedReq)}
-    catch ?STACKTRACE(Tag, Error, Stack)
+    catch Tag:Error:Stack ->
         {HttpReq, catch_error(HttpReq, Tag, Error, Stack)}
     end.
 
diff --git a/src/chttpd/src/chttpd_handlers.erl b/src/chttpd/src/chttpd_handlers.erl
index 43631c0..ce47820 100644
--- a/src/chttpd/src/chttpd_handlers.erl
+++ b/src/chttpd/src/chttpd_handlers.erl
@@ -44,7 +44,7 @@ handler_info(HttpReq) ->
     Default = {'unknown.unknown', #{}},
     try
         select(collect(handler_info, [Method, PathParts, HttpReq]), Default)
-    catch ?STACKTRACE(Type, Reason, Stack)
+    catch Type:Reason:Stack ->
         couch_log:error("~s :: handler_info failure for ~p : ~p:~p :: ~p", [
                 ?MODULE,
                 get(nonce),
diff --git a/src/chttpd/src/chttpd_stats.erl b/src/chttpd/src/chttpd_stats.erl
index ae1efa4..fa2036e 100644
--- a/src/chttpd/src/chttpd_stats.erl
+++ b/src/chttpd/src/chttpd_stats.erl
@@ -12,8 +12,6 @@
 
 -module(chttpd_stats).
 
-% for the stacktrace macro only so far
--include_lib("couch/include/couch_db.hrl").
 
 -export([
     init/1,
@@ -63,7 +61,7 @@ report(HttpResp) ->
             _ ->
                 ok
         end
-    catch ?STACKTRACE(T, R, S)
+    catch T:R:S ->
         Fmt = "Failed to report chttpd request stats: ~p:~p ~p",
         couch_log:error(Fmt, [T, R, S])
     end.
diff --git a/src/couch/include/couch_db.hrl b/src/couch/include/couch_db.hrl
index 01dc0f4..2289089 100644
--- a/src/couch/include/couch_db.hrl
+++ b/src/couch/include/couch_db.hrl
@@ -178,27 +178,3 @@
 
 -define(record_to_keyval(Name, Record),
     lists:zip(record_info(fields, Name), tl(tuple_to_list(Record)))).
-
-%% Erlang/OTP 21 deprecates and 23 removes get_stacktrace(), so
-%% we have to monkey around until we can drop support < 21.
-%% h/t https://github.com/erlang/otp/pull/1783#issuecomment-386190970
-
-%% use like so:
-% try function1(Arg1)
-% catch
-%     ?STACKTRACE(exit, badarg, ErrorStackTrace)
-%         % do stuff with ErrorStackTrace
-%         % ...
-% end,
-
-% Get the stacktrace in a way that is backwards compatible
-% OTP_RELEASE is only available in OTP 21 and later, so we don’t need
-% to do any other version magic here.
--ifdef(OTP_RELEASE).
--define(STACKTRACE(ErrorType, Error, Stack),
-        ErrorType:Error:Stack ->).
--else.
--define(STACKTRACE(ErrorType, Error, Stack),
-        ErrorType:Error ->
-            Stack = erlang:get_stacktrace(),).
--endif.
diff --git a/src/couch/src/couch_proc_manager.erl b/src/couch/src/couch_proc_manager.erl
index 6a0322c..3faef09 100644
--- a/src/couch/src/couch_proc_manager.erl
+++ b/src/couch/src/couch_proc_manager.erl
@@ -321,7 +321,7 @@ find_proc(#client{lang = Lang, ddoc = DDoc, ddoc_key = DDocKey} = Client) ->
 
 find_proc(Lang, Fun) ->
     try iter_procs(Lang, Fun)
-    catch ?STACKTRACE(error, Reason, StackTrace)
+    catch error:Reason:StackTrace ->
         couch_log:error("~p ~p ~p", [?MODULE, Reason, StackTrace]),
         {error, Reason}
     end.
diff --git a/src/couch_js/src/couch_js_proc_manager.erl b/src/couch_js/src/couch_js_proc_manager.erl
index 4b3354d..d9c3efc 100644
--- a/src/couch_js/src/couch_js_proc_manager.erl
+++ b/src/couch_js/src/couch_js_proc_manager.erl
@@ -320,7 +320,7 @@ find_proc(#client{lang = Lang, ddoc = DDoc, ddoc_key = DDocKey} = Client) ->
 
 find_proc(Lang, Fun) ->
     try iter_procs(Lang, Fun)
-    catch ?STACKTRACE(error, Reason, StackTrace)
+    catch error:Reason:StackTrace ->
         couch_log:error("~p ~p ~p", [?MODULE, Reason, StackTrace]),
         {error, Reason}
     end.
diff --git a/src/couch_replicator/src/couch_replicator_job.erl b/src/couch_replicator/src/couch_replicator_job.erl
index d11bdb7..8cfb426 100644
--- a/src/couch_replicator/src/couch_replicator_job.erl
+++ b/src/couch_replicator/src/couch_replicator_job.erl
@@ -221,11 +221,9 @@ handle_info(timeout, delayed_init) ->
         {ok, State} -> {noreply, State};
         {stop, Reason, State} -> {stop, Reason, State}
     catch
-        ?STACKTRACE(exit, {shutdown, finished}, Stack)
-            {stop, {shutdown, finished}, {init_error, Stack}};
-        ?STACKTRACE(exit, {shtudown, halt}, Stack)
-            {stop, {shutdown, halt}, {init_error, Stack}};
-        ?STACKTRACE(_Tag, Error, Stack)
+        exit:{shutdown, Exit}:Stack when Exit =:= finished orelse Exit =:= halt ->
+            {stop, {shutdown, Exit}, {init_error, Stack}};
+        _Tag:Error:Stack ->
             ShutdownReason = {error, replication_start_error(Error)},
             {stop, {shutdown, ShutdownReason}, {init_error, Stack}}
     end;
@@ -406,14 +404,12 @@ delayed_init() ->
     try do_init(Job, JobData) of
         State = #rep_state{} -> {ok, State}
     catch
-        ?STACKTRACE(exit, {http_request_failed, _, _, max_backoff}, Stack)
+        exit:{http_request_failed, _, _, max_backoff}:Stack ->
             reschedule_on_error(undefined, Job, JobData, max_backoff),
             {stop, {shutdown, max_backoff}, {init_error, Stack}};
-        ?STACKTRACE(exit, {shutdown, finished}, Stack)
-            {stop, {shutdown, finished}, {init_error, Stack}};
-        ?STACKTRACE(exit, {shutdown, halt}, Stack)
-            {stop, {shutdown, halt}, {init_error, Stack}};
-        ?STACKTRACE(_Tag, Error, Stack)
+        exit:{shutdown, Exit}:Stack when Exit =:= finished orelse Exit =:= halt ->
+            {stop, {shutdown, Exit}, {init_error, Stack}};
+        _Tag:Error:Stack ->
             Reason = {error, replication_start_error(Error)},
             ErrMsg = "~p : job ~p failed during startup ~p stack:~p",
             couch_log:error(ErrMsg, [?MODULE, Job, Reason, Stack]),
diff --git a/src/couch_replicator/src/couch_replicator_parse.erl b/src/couch_replicator/src/couch_replicator_parse.erl
index 79c778d..5b3f3f3 100644
--- a/src/couch_replicator/src/couch_replicator_parse.erl
+++ b/src/couch_replicator/src/couch_replicator_parse.erl
@@ -22,7 +22,6 @@
 
 
 -include_lib("ibrowse/include/ibrowse.hrl").
--include_lib("couch/include/couch_db.hrl").
 -include("couch_replicator.hrl").
 
 
@@ -60,11 +59,11 @@ parse_rep_doc(RepDoc) ->
     {ok, Rep} = try
         parse_rep(RepDoc, null)
     catch
-        ?STACKTRACE(throw, {error, Reason}, Stack)
+        throw:{error, Reason}:Stack ->
             LogErr1 = "~p parse_rep_doc fail ~p ~p",
             couch_log:error(LogErr1, [?MODULE, Reason, Stack]),
             throw({bad_rep_doc, Reason});
-        ?STACKTRACE(Tag, Err, Stack)
+        Tag:Err:Stack ->
             LogErr2 = "~p parse_rep_doc fail ~p:~p ~p",
             couch_log:error(LogErr2, [?MODULE, Tag, Err, Stack]),
             throw({bad_rep_doc, couch_util:to_binary({Tag, Err})})
@@ -82,11 +81,11 @@ parse_transient_rep(#{} = Body, UserName) ->
     {ok, Rep} = try
         parse_rep(Body, UserName)
     catch
-        ?STACKTRACE(throw, {error, Reason}, Stack)
+        throw:{error, Reason}:Stack ->
             LogErr1 = "~p parse_transient_rep fail ~p ~p",
             couch_log:error(LogErr1, [?MODULE, Reason, Stack]),
             throw({bad_request, Reason});
-        ?STACKTRACE(Tag, Err, Stack)
+        Tag:Err:Stack ->
             LogErr2 = "~p parse_transient_rep fail ~p ~p",
             couch_log:error(LogErr2, [?MODULE, Tag, Err, Stack]),
             throw({bad_request, couch_util:to_binary({Tag, Err})})
diff --git a/src/couch_views/src/couch_views_indexer.erl b/src/couch_views/src/couch_views_indexer.erl
index 2164a58..eed3f54 100644
--- a/src/couch_views/src/couch_views_indexer.erl
+++ b/src/couch_views/src/couch_views_indexer.erl
@@ -121,7 +121,7 @@ init() ->
             ok;
         error:database_does_not_exist ->
             fail_job(Job, Data, db_deleted, "Database was deleted");
-        ?STACKTRACE(Error, Reason, Stack)
+        Error:Reason:Stack ->
             Fmt = "Error building view for ddoc ~s in ~s: ~p:~p ~p",
             couch_log:error(Fmt, [DbName, DDocId, Error, Reason, Stack]),
 
diff --git a/src/couch_views/src/couch_views_updater.erl b/src/couch_views/src/couch_views_updater.erl
index 7c96bb8..c7d3146 100644
--- a/src/couch_views/src/couch_views_updater.erl
+++ b/src/couch_views/src/couch_views_updater.erl
@@ -31,7 +31,7 @@ index(Db, #doc{id = Id, revs = Revs} = Doc, _NewWinner, _OldWinner, NewRevId,
             index_int(Db, Doc, Seq)
         end
     catch
-        ?STACKTRACE(error, {erlfdb_error, ErrCode}, Stack)
+        error:{erlfdb_error, ErrCode}:Stack when is_integer(ErrCode) ->
             DbName = fabric2_db:name(Db),
             couch_log:error("Mango index erlfdb error Db ~s Doc ~p ~p",
                 [DbName, Id, ErrCode]),
diff --git a/src/ctrace/src/ctrace.erl b/src/ctrace/src/ctrace.erl
index 8ae51c4..a890bde 100644
--- a/src/ctrace/src/ctrace.erl
+++ b/src/ctrace/src/ctrace.erl
@@ -109,7 +109,7 @@ with_span(Operation, Options, Fun)  ->
     try
         start_span(Operation, Options),
         Fun()
-    catch ?STACKTRACE(Type, Reason, Stack)
+    catch Type:Reason:Stack ->
         log(#{
             ?LOG_FIELD_ERROR_KIND => Type,
             ?LOG_FIELD_MESSAGE => Reason,
diff --git a/src/fabric/src/fabric2_db_expiration.erl b/src/fabric/src/fabric2_db_expiration.erl
index 94cb61b..b438591 100644
--- a/src/fabric/src/fabric2_db_expiration.erl
+++ b/src/fabric/src/fabric2_db_expiration.erl
@@ -131,7 +131,7 @@ cleanup(true) ->
                 {ok, Job1, Data1} = ?MODULE:process_expirations(Job, Data),
                 ok = resubmit_job(Job1, Data1, schedule_sec())
             catch
-                ?STACKTRACE(_Tag, Error, Stack)
+                _Tag:Error:Stack ->
                     couch_log:error("~p : processing error ~p ~p ~p",
                         [?MODULE, Job, Error, Stack]),
                     ok = resubmit_job(Job, Data, ?ERROR_RESCHEDULE_SEC),
diff --git a/src/fabric/src/fabric2_index.erl b/src/fabric/src/fabric2_index.erl
index 3c59cd7..037f0f5 100644
--- a/src/fabric/src/fabric2_index.erl
+++ b/src/fabric/src/fabric2_index.erl
@@ -67,7 +67,7 @@ cleanup(Db) ->
     catch
         error:database_does_not_exist ->
             ok;
-        ?STACKTRACE(Tag, Reason, Stack)
+        Tag:Reason:Stack ->
             DbName = fabric2_db:name(Db),
             LogMsg = "~p failed to cleanup indices for `~s` ~p:~p ~p",
             couch_log:error(LogMsg, [?MODULE, DbName, Tag, Reason, Stack])
@@ -167,7 +167,7 @@ process_updates_iter([Db | Rest], Cont) ->
     catch
         error:database_does_not_exist ->
             ok;
-        ?STACKTRACE(Tag, Reason, Stack)
+        Tag:Reason:Stack ->
             LogMsg = "~p failed to build indices for `~s` ~p:~p ~p",
             couch_log:error(LogMsg, [?MODULE, Db, Tag, Reason, Stack])
     end,
diff --git a/src/fabric/src/fabric2_util.erl b/src/fabric/src/fabric2_util.erl
index f95e410..cd22778 100644
--- a/src/fabric/src/fabric2_util.erl
+++ b/src/fabric/src/fabric2_util.erl
@@ -386,6 +386,6 @@ pmap(Fun, Args, Opts) ->
 pmap_exec(Fun, Arg) ->
     try
         {'$res', Fun(Arg)}
-    catch ?STACKTRACE(Tag, Reason, Stack)
+    catch Tag:Reason:Stack ->
         {'$err', Tag, Reason, Stack}
     end.
diff --git a/src/mango/src/mango_httpd.erl b/src/mango/src/mango_httpd.erl
index 9ac4dfc..0d035dd 100644
--- a/src/mango/src/mango_httpd.erl
+++ b/src/mango/src/mango_httpd.erl
@@ -36,7 +36,7 @@ handle_req(#httpd{} = Req, Db) ->
     try
         handle_req_int(Req, Db)
     catch
-        ?STACKTRACE(throw, {mango_error, Module, Reason}, Stack)
+        throw:{mango_error, Module, Reason}:Stack ->
             case mango_error:info(Module, Reason) of
             {500, ErrorStr, ReasonStr} ->
                 chttpd:send_error(Req, {ErrorStr, ReasonStr, Stack});

[couchdb] 03/03: Add a temporary logger config

Posted by ko...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kocolosk pushed a commit to branch new-logger
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 0a6200d86c18560f05cb07c9fb65b096a802a7d3
Author: Adam Kocoloski <ko...@apache.org>
AuthorDate: Thu Apr 22 20:45:20 2021 +0000

    Add a temporary logger config
---
 rel/files/sys.config | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/rel/files/sys.config b/rel/files/sys.config
index 97562f5..7ea70b5 100644
--- a/rel/files/sys.config
+++ b/rel/files/sys.config
@@ -10,4 +10,32 @@
 % License for the specific language governing permissions and limitations under
 % the License.
 
-[].
+[
+    {kernel, [
+        {logger, [
+            {handler, access, logger_std_h,
+                #{
+                    config => #{
+                        file => "dev/logs/access.log"
+                    },
+                    filters => [
+                        {access_logs, {fun logger_filters:domain/2, {log, equal, [chttpd_access_log]}}}
+                    ],
+                    filter_default => stop,
+                    formatter => {logger_formatter, #{}}
+                }
+            },
+            {handler, debug, logger_std_h,
+                #{
+                    config => #{
+                        file => "dev/logs/debug.log"
+                    },
+                    filters => [
+                        % comment this filter out to include access logs in the debug log as well
+                        {access_logs, {fun logger_filters:domain/2, {stop, equal, [chttpd_access_log]}}}
+                    ]
+                }
+            }
+        ]}
+       ]}
+].