<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>