<HTML><BODY><div class="js-helper js-readmsg-msg">
<style type="text/css"></style>
<div>
<base target="_self" href="https://e.mail.ru/">
<div id="style_15222241950000000229_BODY"><div class="class_1522225715"><div class="js-helper_mailru_css_attribute_postfix js-readmsg-msg_mailru_css_attribute_postfix"><div><div id="style_15221803420000000937_BODY_mailru_css_attribute_postfix">* Remove rewriting format of default logger in case of syslog option.<br>
* Add facility option parsing and use parsed results in format message<br>
according to RFC3164. Possible values and default value of syslog<br>
facility are taken from nginx(<a href="https://nginx.ru/en/docs/syslog.html" target="_blank">https://nginx.ru/en/docs/syslog.html</a>)<br>
<br>
Closes #3244<br>
<br>
branch: gh-3244-syslog-facility <br>
---<br>
src/say.c | 74 +++++++++++++++++++++++++++++++++++++++++++---------<br>
src/say.h | 31 +++++++++++++++++++++-<br>
test/unit/say.c | 26 +++++++++++++++---<br>
test/unit/say.result | 33 +++++++++++++++--------<br>
4 files changed, 135 insertions(+), 29 deletions(-)<br>
<br>
diff --git a/src/say.c b/src/say.c<br>
index b92514d..68e3b09 100644<br>
--- a/src/say.c<br>
+++ b/src/say.c<br>
@@ -191,16 +191,17 @@ say_set_log_level(int new_level)<br>
void<br>
say_set_log_format(enum say_format format)<br>
{<br>
-<br>
+ /*<br>
+ * For syslog, default or boot log type the log format can<br>
+ * not be changed.<br>
+ */<br>
+ bool allowed_to_change = log_default->type == SAY_LOGGER_STDERR ||<br>
+ log_default->type == SAY_LOGGER_PIPE ||<br>
+ log_default->type == SAY_LOGGER_FILE;<br>
switch (format) {<br>
case SF_JSON:<br>
- /*<br>
- * For syslog, default or boot log type the log format can<br>
- * not be changed.<br>
- */<br>
- if (log_default->type != SAY_LOGGER_STDERR &&<br>
- log_default->type != SAY_LOGGER_PIPE &&<br>
- log_default->type != SAY_LOGGER_FILE) {<br>
+<br>
+ if (!allowed_to_change) {<br>
say_error("json log format is not supported when output is '%s'",<br>
say_logger_type_strs[log_default->type]);<br>
return;<br>
@@ -208,6 +209,9 @@ say_set_log_format(enum say_format format)<br>
log_set_format(log_default, say_format_json);<br>
break;<br>
case SF_PLAIN:<br>
+ if (!allowed_to_change) {<br>
+ return;<br>
+ }<br>
log_set_format(log_default, say_format_plain);<br>
break;<br>
default:<br>
@@ -477,6 +481,11 @@ log_syslog_init(struct log *log, const char *init_str)<br>
log->syslog_ident = strdup("tarantool");<br>
else<br>
log->syslog_ident = strdup(opts.identity);<br>
+<br>
+ if (opts.facility == syslog_facility_MAX)<br>
+ log->syslog_facility = SYSLOG_LOCAL7;<br>
+ else<br>
+ log->syslog_facility = opts.facility;<br>
say_free_syslog_opts(&opts);<br>
log->fd = log_syslog_connect(log);<br>
if (log->fd < 0) {<br>
@@ -814,14 +823,14 @@ say_format_syslog(struct log *log, char *buf, int len, int level, const char *fi<br>
<br>
/* Format syslog header according to RFC */<br>
int prio = level_to_syslog_priority(level);<br>
- SNPRINT(total, snprintf, buf, len, "<%d>", LOG_MAKEPRI(1, prio));<br>
+ SNPRINT(total, snprintf, buf, len, "<%d>",<br>
+ LOG_MAKEPRI(8 * log->syslog_facility, prio));<br>
SNPRINT(total, strftime, buf, len, "%h %e %T ", &tm);<br>
SNPRINT(total, snprintf, buf, len, "%s[%d]:", log->syslog_ident, getpid());<br>
<br>
/* Format message */<br>
SNPRINT(total, say_format_plain_tail, buf, len, level, filename, line,<br>
error, format, ap);<br>
-<br>
return total;<br>
}<br>
<br>
@@ -963,11 +972,45 @@ say_parse_logger_type(const char **str, enum say_logger_type *type)<br>
return 0;<br>
}<br>
<br>
+static const char *syslog_facility_strs[] = {<br>
+ [SYSLOG_KERN] = "kern",<br>
+ [SYSLOG_USER] = "user",<br>
+ [SYSLOG_MAIL] = "mail",<br>
+ [SYSLOG_DAEMON] = "daemon",<br>
+ [SYSLOG_AUTH] = "auth",<br>
+ [SYSLOG_INTERN] = "intern",<br>
+ [SYSLOG_LPR] = "lpr",<br>
+ [SYSLOG_NEWS] = "news",<br>
+ [SYSLOG_UUCP] = "uucp",<br>
+ [SYSLOG_CLOCK] = "clock",<br>
+ [SYSLOG_AUTHPRIV] = "authpriv",<br>
+ [SYSLOG_FTP] = "ftp",<br>
+ [SYSLOG_NTP] = "ntp",<br>
+ [SYSLOG_AUDIT] = "audit",<br>
+ [SYSLOG_ALERT] = "alert",<br>
+ [SYSLOG_CRON] = "cron",<br>
+ [SYSLOG_LOCAL0] = "local0",<br>
+ [SYSLOG_LOCAL1] = "local1",<br>
+ [SYSLOG_LOCAL2] = "local2",<br>
+ [SYSLOG_LOCAL3] = "local3",<br>
+ [SYSLOG_LOCAL4] = "local4",<br>
+ [SYSLOG_LOCAL5] = "local5",<br>
+ [SYSLOG_LOCAL6] = "local6",<br>
+ [SYSLOG_LOCAL7] = "local7",<br>
+ [syslog_facility_MAX] = "unknown",<br>
+};<br>
+<br>
+enum syslog_facility<br>
+say_syslog_facility_by_name(const char *facility)<br>
+{<br>
+ return STR2ENUM(syslog_facility, facility);<br>
+}<br>
+<br>
int<br>
say_parse_syslog_opts(const char *init_str, struct say_syslog_opts *opts)<br>
{<br>
opts->identity = NULL;<br>
- opts->facility = NULL;<br>
+ opts->facility = syslog_facility_MAX;<br>
opts->copy = strdup(init_str);<br>
if (opts->copy == NULL) {<br>
diag_set(OutOfMemory, strlen(init_str), "malloc", "opts->copy");<br>
@@ -987,9 +1030,14 @@ say_parse_syslog_opts(const char *init_str, struct say_syslog_opts *opts)<br>
goto duplicate;<br>
opts->identity = value;<br>
} else if (say_parse_prefix(&value, "facility=")) {<br>
- if (opts->facility != NULL)<br>
+ if (opts->facility != syslog_facility_MAX)<br>
goto duplicate;<br>
- opts->facility = value;<br>
+ opts->facility = say_syslog_facility_by_name(value);<br>
+ if (opts->facility == syslog_facility_MAX) {<br>
+ diag_set(IllegalParams, "bad syslog facility option '%s'",<br>
+ value);<br>
+ goto error;<br>
+ }<br>
} else {<br>
diag_set(IllegalParams, "bad option '%s'", option);<br>
goto error;<br>
diff --git a/src/say.h b/src/say.h<br>
index 46e6976..0703c6a 100644<br>
--- a/src/say.h<br>
+++ b/src/say.h<br>
@@ -97,6 +97,34 @@ enum say_logger_type {<br>
SAY_LOGGER_SYSLOG<br>
};<br>
<br>
+enum syslog_facility {<br>
+ SYSLOG_KERN = 0,<br>
+ SYSLOG_USER,<br>
+ SYSLOG_MAIL,<br>
+ SYSLOG_DAEMON,<br>
+ SYSLOG_AUTH,<br>
+ SYSLOG_INTERN,<br>
+ SYSLOG_LPR,<br>
+ SYSLOG_NEWS,<br>
+ SYSLOG_UUCP,<br>
+ SYSLOG_CLOCK,<br>
+ SYSLOG_AUTHPRIV,<br>
+ SYSLOG_FTP,<br>
+ SYSLOG_NTP,<br>
+ SYSLOG_AUDIT,<br>
+ SYSLOG_ALERT,<br>
+ SYSLOG_CRON,<br>
+ SYSLOG_LOCAL0,<br>
+ SYSLOG_LOCAL1,<br>
+ SYSLOG_LOCAL2,<br>
+ SYSLOG_LOCAL3,<br>
+ SYSLOG_LOCAL4,<br>
+ SYSLOG_LOCAL5,<br>
+ SYSLOG_LOCAL6,<br>
+ SYSLOG_LOCAL7,<br>
+ syslog_facility_MAX,<br>
+};<br>
+<br>
struct log;<br>
<br>
typedef int (*log_format_func_t)(struct log *log, char *buf, int len, int level,<br>
@@ -119,6 +147,7 @@ struct log {<br>
pid_t pid;<br>
/* Application identifier used to group syslog messages. */<br>
char *syslog_ident;<br>
+ enum syslog_facility syslog_facility;<br>
struct rlist in_log_list;<br>
};<br>
<br>
@@ -349,7 +378,7 @@ say_parse_logger_type(const char **str, enum say_logger_type *type);<br>
/** Syslog logger initialization params */<br>
struct say_syslog_opts {<br>
const char *identity;<br>
- const char *facility;<br>
+ enum syslog_facility facility;<br>
/* Input copy (content unspecified). */<br>
char *copy;<br>
};<br>
diff --git a/test/unit/say.c b/test/unit/say.c<br>
index 8c996ba..4e5de75 100644<br>
--- a/test/unit/say.c<br>
+++ b/test/unit/say.c<br>
@@ -39,7 +39,7 @@ parse_syslog_opts(const char *input)<br>
if (opts.identity)<br>
note("identity: %s", opts.identity);<br>
if (opts.facility)<br>
- note("facility: %s", opts.facility);<br>
+ note("facility: %i", opts.facility);<br>
say_free_syslog_opts(&opts);<br>
return 0;<br>
}<br>
@@ -124,7 +124,7 @@ int main()<br>
fiber_init(fiber_c_invoke);<br>
say_logger_init("/dev/null", S_INFO, 0, "plain", 0);<br>
<br>
- plan(23);<br>
+ plan(29);<br>
<br>
#define PARSE_LOGGER_TYPE(input, rc) \<br>
ok(parse_logger_type(input) == rc, "%s", input)<br>
@@ -149,7 +149,10 @@ int main()<br>
PARSE_SYSLOG_OPTS("identity=tarantool", 0);<br>
PARSE_SYSLOG_OPTS("facility=user", 0);<br>
PARSE_SYSLOG_OPTS("identity=xtarantoolx,facility=local1", 0);<br>
- PARSE_SYSLOG_OPTS("facility=foo,identity=bar", 0);<br>
+ PARSE_SYSLOG_OPTS("identity=xtarantoolx,facility=kern", 0);<br>
+ PARSE_SYSLOG_OPTS("identity=xtarantoolx,facility=uucp", 0);<br>
+ PARSE_SYSLOG_OPTS("identity=xtarantoolx,facility=foo", -1);<br>
+ PARSE_SYSLOG_OPTS("facility=authpriv,identity=bar", 0);<br>
PARSE_SYSLOG_OPTS("invalid=", -1);<br>
PARSE_SYSLOG_OPTS("facility=local1,facility=local2", -1);<br>
PARSE_SYSLOG_OPTS("identity=foo,identity=bar", -1);<br>
@@ -170,7 +173,7 @@ int main()<br>
log_set_format(&test_log, format_func_custom);<br>
log_say(&test_log, 0, NULL, 0, NULL, "hello %s", "user");<br>
<br>
- FILE* fd = fopen(tmp_filename, "r");<br>
+ FILE* fd = fopen(tmp_filename, "r+");<br>
const size_t len = 4096;<br>
char line[len];<br>
<br>
@@ -187,6 +190,21 @@ int main()<br>
}<br>
log_destroy(&test_log);<br>
<br>
+ log_create(&test_log, "syslog:identity=tarantool,facility=local0", false);<br>
+ test_log.fd = fileno(fd);<br>
+ /* redirect stderr to /dev/null in order to filter<br>
+ * it out from result file.<br>
+ */<br>
+ freopen("/dev/null", "w", stderr);<br>
+ ok(strncmp(test_log.syslog_ident, "tarantool", 9) == 0, "parsed identity");<br>
+ ok(test_log.syslog_facility == SYSLOG_LOCAL0, "parsed facility");<br>
+ long before = ftell(fd);<br>
+ log_say(&test_log, 0, NULL, 0, NULL, "hello %s", "user");<br>
+ fseek(fd, before, SEEK_SET);<br>
+<br>
+ if (fgets(line, len, fd) != NULL) {<br>
+ ok(strstr(line, "<131>") != NULL, "syslog line");<br>
+ }<br>
// test on log_rotate signal handling<br>
struct ev_signal ev_sig;<br>
ev_signal_init(&ev_sig, say_logrotate, SIGHUP);<br>
diff --git a/test/unit/say.result b/test/unit/say.result<br>
index dfd3fc0..db7befb 100644<br>
--- a/test/unit/say.result<br>
+++ b/test/unit/say.result<br>
@@ -1,4 +1,4 @@<br>
-1..23<br>
+1..29<br>
# type: file<br>
# next: <br>
ok 1 - <br>
@@ -33,20 +33,31 @@ ok 10 - syslog:identity=<br>
ok 11 - unknown:<br>
# next: unknown:example.org<br>
ok 12 - unknown:example.org<br>
+# facility: 24<br>
ok 13 - <br>
# identity: tarantool<br>
+# facility: 24<br>
ok 14 - identity=tarantool<br>
-# facility: user<br>
+# facility: 1<br>
ok 15 - facility=user<br>
# identity: xtarantoolx<br>
-# facility: local1<br>
+# facility: 17<br>
ok 16 - identity=xtarantoolx,facility=local1<br>
+# identity: xtarantoolx<br>
+ok 17 - identity=xtarantoolx,facility=kern<br>
+# identity: xtarantoolx<br>
+# facility: 8<br>
+ok 18 - identity=xtarantoolx,facility=uucp<br>
+ok 19 - identity=xtarantoolx,facility=foo<br>
# identity: bar<br>
-# facility: foo<br>
-ok 17 - facility=foo,identity=bar<br>
-ok 18 - invalid=<br>
-ok 19 - facility=local1,facility=local2<br>
-ok 20 - identity=foo,identity=bar<br>
-ok 21 - plain<br>
-ok 22 - json<br>
-ok 23 - custom<br>
+# facility: 10<br>
+ok 20 - facility=authpriv,identity=bar<br>
+ok 21 - invalid=<br>
+ok 22 - facility=local1,facility=local2<br>
+ok 23 - identity=foo,identity=bar<br>
+ok 24 - plain<br>
+ok 25 - json<br>
+ok 26 - custom<br>
+ok 27 - parsed identity<br>
+ok 28 - parsed facility<br>
+ok 29 - syslog line<br>
-- <br>
2.7.4<br>
<br>
</div>
</div>
</div>
<br><hr>
<br>-- <br>Thank you,<br>Ilya Markov<br>
</div></div>
<base target="_self" href="https://e.mail.ru/">
</div>
</div><style></style></BODY></HTML>