a systemd-journald compatible log output on stderr (#1912)

* a systemd-journald compatible log output on stderr

based on the stderr logger but changed:
- doesn't output the timestamp, the journal already has a timestamp
- output the log level as <num> where num is defined as in `sd-daemon(3)`

https://www.freedesktop.org/software/systemd/man/sd-daemon.html
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index d8476f3..9a8c70b 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -449,16 +449,25 @@
 ; max_message_size = 16000
 ;
 ;
-; There are three different log writers that can be configured
+; There are four different log writers that can be configured
 ; to write log messages. The default writes to stderr of the
 ; Erlang VM which is useful for debugging/development as well
 ; as a lot of container deployments.
 ;
-; There's also a file writer that works with logrotate and an
+; There's also a file writer that works with logrotate, a
 ; rsyslog writer for deployments that need to have logs sent
-; over the network.
+; over the network, and a journald writer that's more suitable
+; when using systemd journald.
 ;
 writer = stderr
+; Journald Writer notes:
+;
+; The journald writer doesn't have any options. It still writes
+; the logs to stderr, but without the timestamp prepended, since
+; the journal will add it automatically, and with the log level
+; formated as per
+; https://www.freedesktop.org/software/systemd/man/sd-daemon.html
+;
 ;
 ; File Writer Options:
 ;
@@ -525,4 +534,4 @@
 ; value will be rejected. If this config setting is not defined,
 ; CouchDB will use the value of `max_limit` instead. If neither is
 ; defined, the default is 2000 as stated here.
-; max_limit_partitions = 2000
\ No newline at end of file
+; max_limit_partitions = 2000
diff --git a/src/couch_log/src/couch_log_writer_journald.erl b/src/couch_log/src/couch_log_writer_journald.erl
new file mode 100644
index 0000000..02a9c69
--- /dev/null
+++ b/src/couch_log/src/couch_log_writer_journald.erl
@@ -0,0 +1,69 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_log_writer_journald).
+-behaviour(couch_log_writer).
+
+
+-export([
+    init/0,
+    terminate/2,
+    write/2
+]).
+
+
+-include("couch_log.hrl").
+
+
+init() ->
+    {ok, nil}.
+
+
+terminate(_, _St) ->
+    ok.
+
+
+write(Entry, St) ->
+    #log_entry{
+        level = Level,
+        pid = Pid,
+        msg = Msg,
+        msg_id = MsgId
+    } = Entry,
+    Fmt = "<~B>~s ~p ~s ",
+    Args = [
+        level_for_journald(Level),
+        node(),
+        Pid,
+        MsgId
+    ],
+    MsgSize = couch_log_config:get(max_message_size),
+    Data = couch_log_trunc_io:format(Fmt, Args, MsgSize),
+    io:format(standard_error, [Data, Msg, "\n"], []),
+    {ok, St}.
+
+
+% log level mapping from sd-daemon(3)
+% https://www.freedesktop.org/software/systemd/man/sd-daemon.html
+-spec level_for_journald(atom()) -> integer().
+level_for_journald(Level) when is_atom(Level) ->
+    case Level of
+        debug       -> 7;
+        info        -> 6;
+        notice      -> 5;
+        warning     -> 4;
+        error       -> 3;
+        critical    -> 2;
+        alert       -> 1;
+        emergency   -> 0;
+        _           -> 3
+    end.