daemon: add --log-destination=(stderr|syslog|none)

This new option can be used to override the implicit --syslog of --inetd, or to disable all logging. (While --detach also implies --syslog, --log-destination=stderr with --detach is useless since --detach disassociates the process from the original stderr.) --syslog is retained as an alias for --log-destination=syslog. --log-destination always overrides implicit --syslog regardless of option order. This is different than the “last one wins” logic that applies to some implicit options elsewhere in Git, but should hopefully be less confusing. (I also don’t know if *all* implicit options in Git follow “last one wins”.) The combination of --inetd with --log-destination=stderr is useful, for instance, when running `git daemon` as an instanced systemd service (with associated socket unit). In this case, log messages sent via syslog are received by the journal daemon, but run the risk of being processed at a time when the `git daemon` process has already exited (especially if the process was very short-lived, e.g. due to client error), so that the journal daemon can no longer read its cgroup and attach the message to the correct systemd unit (see systemd/systemd#2913 [1]). Logging to stderr instead can solve this problem, because systemd can connect stderr directly to the journal daemon, which then already knows which unit is associated with this stream. [1]: https://github.com/systemd/systemd/issues/2913 Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Lucas Werkmeister <mail@lucaswerkmeister.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Lucas Werkmeister committed Feb 4, 2018 at 19:30 UTC 0c591cacba00a36af797fa3b6c4a4f12d342be86
2 files changed +64 -10
Documentation/git-daemon.txt
+25 -3
@@ -20,6 +20,7 @@ SYNOPSIS
20 [--inetd |
21 [--listen=<host_or_ipaddr>] [--port=<n>]
22 [--user=<user> [--group=<group>]]]
23 + [--log-destination=(stderr|syslog|none)]
24 [<directory>...]
25
26 DESCRIPTION
@@ -80,7 +81,8 @@ OPTIONS
81 do not have the 'git-daemon-export-ok' file.
82
83 --inetd::
83 - Have the server run as an inetd service. Implies --syslog.
84 + Have the server run as an inetd service. Implies --syslog (may be
85 + overridden with `--log-destination=`).
86 Incompatible with --detach, --port, --listen, --user and --group
87 options.
88
@@ -110,8 +112,28 @@ OPTIONS
112 zero for no limit.
113
114 --syslog::
113 - Log to syslog instead of stderr. Note that this option does not imply
114 - --verbose, thus by default only error conditions will be logged.
115 + Short for `--log-destination=syslog`.
116 +
117 +--log-destination=<destination>::
118 + Send log messages to the specified destination.
119 + Note that this option does not imply --verbose,
120 + thus by default only error conditions will be logged.
121 + The <destination> must be one of:
122 ++
123 +--
124 +stderr::
125 + Write to standard error.
126 + Note that if `--detach` is specified,
127 + the process disconnects from the real standard error,
128 + making this destination effectively equivalent to `none`.
129 +syslog::
130 + Write to syslog, using the `git-daemon` identifier.
131 +none::
132 + Disable all logging.
133 +--
134 ++
135 +The default destination is `syslog` if `--inetd` or `--detach` is specified,
136 +otherwise `stderr`.
137
138 --user-path::
139 --user-path=<path>::
daemon.c
+39 -7
@@ -9,7 +9,12 @@
9 #define initgroups(x, y) (0) /* nothing */
10 #endif
11
12 -static int log_syslog;
12 +static enum log_destination {
13 + LOG_DESTINATION_UNSET = -1,
14 + LOG_DESTINATION_NONE = 0,
15 + LOG_DESTINATION_STDERR = 1,
16 + LOG_DESTINATION_SYSLOG = 2,
17 +} log_destination = LOG_DESTINATION_UNSET;
18 static int verbose;
19 static int reuseaddr;
20 static int informative_errors;
@@ -25,6 +30,7 @@ static const char daemon_usage[] =
30 " [--access-hook=<path>]\n"
31 " [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
32 " [--detach] [--user=<user> [--group=<group>]]\n"
33 +" [--log-destination=(stderr|syslog|none)]\n"
34 " [<directory>...]";
35
36 /* List of acceptable pathname prefixes */
@@ -74,11 +80,14 @@ static const char *get_ip_address(struct hostinfo *hi)
80
81 static void logreport(int priority, const char *err, va_list params)
82 {
77 - if (log_syslog) {
83 + switch (log_destination) {
84 + case LOG_DESTINATION_SYSLOG: {
85 char buf[1024];
86 vsnprintf(buf, sizeof(buf), err, params);
87 syslog(priority, "%s", buf);
81 - } else {
88 + break;
89 + }
90 + case LOG_DESTINATION_STDERR:
91 /*
92 * Since stderr is set to buffered mode, the
93 * logging of different processes will not overlap
@@ -88,6 +97,11 @@ static void logreport(int priority, const char *err, va_list params)
97 vfprintf(stderr, err, params);
98 fputc('\n', stderr);
99 fflush(stderr);
100 + break;
101 + case LOG_DESTINATION_NONE:
102 + break;
103 + case LOG_DESTINATION_UNSET:
104 + BUG("log destination not initialized correctly");
105 }
106 }
107
@@ -1289,7 +1303,6 @@ int cmd_main(int argc, const char **argv)
1303 }
1304 if (!strcmp(arg, "--inetd")) {
1305 inetd_mode = 1;
1292 - log_syslog = 1;
1306 continue;
1307 }
1308 if (!strcmp(arg, "--verbose")) {
@@ -1297,9 +1310,22 @@ int cmd_main(int argc, const char **argv)
1310 continue;
1311 }
1312 if (!strcmp(arg, "--syslog")) {
1300 - log_syslog = 1;
1313 + log_destination = LOG_DESTINATION_SYSLOG;
1314 continue;
1315 }
1316 + if (skip_prefix(arg, "--log-destination=", &v)) {
1317 + if (!strcmp(v, "syslog")) {
1318 + log_destination = LOG_DESTINATION_SYSLOG;
1319 + continue;
1320 + } else if (!strcmp(v, "stderr")) {
1321 + log_destination = LOG_DESTINATION_STDERR;
1322 + continue;
1323 + } else if (!strcmp(v, "none")) {
1324 + log_destination = LOG_DESTINATION_NONE;
1325 + continue;
1326 + } else
1327 + die("unknown log destination '%s'", v);
1328 + }
1329 if (!strcmp(arg, "--export-all")) {
1330 export_all_trees = 1;
1331 continue;
@@ -1356,7 +1382,6 @@ int cmd_main(int argc, const char **argv)
1382 }
1383 if (!strcmp(arg, "--detach")) {
1384 detach = 1;
1359 - log_syslog = 1;
1385 continue;
1386 }
1387 if (skip_prefix(arg, "--user=", &v)) {
@@ -1402,7 +1427,14 @@ int cmd_main(int argc, const char **argv)
1427 usage(daemon_usage);
1428 }
1429
1405 - if (log_syslog) {
1430 + if (log_destination == LOG_DESTINATION_UNSET) {
1431 + if (inetd_mode || detach)
1432 + log_destination = LOG_DESTINATION_SYSLOG;
1433 + else
1434 + log_destination = LOG_DESTINATION_STDERR;
1435 + }
1436 +
1437 + if (log_destination == LOG_DESTINATION_SYSLOG) {
1438 openlog("git-daemon", LOG_PID, LOG_DAEMON);
1439 set_die_routine(daemon_die);
1440 } else