diff --git a/daemon/logger/syslog/syslog.go b/daemon/logger/syslog/syslog.go index 99e03278ce..088a31eb5e 100644 --- a/daemon/logger/syslog/syslog.go +++ b/daemon/logger/syslog/syslog.go @@ -76,9 +76,20 @@ func rfc5424formatterWithAppNameAsTag(p syslog.Priority, hostname, tag, content return msg } +// The timestamp field in rfc5424 is derived from rfc3339. Whereas rfc3339 makes allowances +// for multiple syntaxes, there are further restrictions in rfc5424, i.e., the maximium +// resolution is limited to "TIME-SECFRAC" which is 6 (microsecond resolution) +func rfc5424microformatterWithAppNameAsTag(p syslog.Priority, hostname, tag, content string) string { + timestamp := time.Now().Format("2006-01-02T15:04:05.999999Z07:00") + pid := os.Getpid() + msg := fmt.Sprintf("<%d>%d %s %s %s %d %s %s", + p, 1, timestamp, hostname, tag, pid, tag, content) + return msg +} + // New creates a syslog logger using the configuration passed in on // the context. Supported context configuration variables are -// syslog-address, syslog-facility, & syslog-tag. +// syslog-address, syslog-facility, syslog-format, syslog-tag. func New(ctx logger.Context) (logger.Logger, error) { tag, err := loggerutils.ParseLogTag(ctx, "{{.ID}}") if err != nil { @@ -240,6 +251,8 @@ func parseLogFormat(logFormat string) (syslog.Formatter, syslog.Framer, error) { return syslog.RFC3164Formatter, syslog.DefaultFramer, nil case "rfc5424": return rfc5424formatterWithAppNameAsTag, syslog.RFC5425MessageLengthFramer, nil + case "rfc5424micro": + return rfc5424microformatterWithAppNameAsTag, syslog.RFC5425MessageLengthFramer, nil default: return nil, nil, errors.New("Invalid syslog format") } diff --git a/daemon/logger/syslog/syslog_test.go b/daemon/logger/syslog/syslog_test.go index c18494be10..f083030b70 100644 --- a/daemon/logger/syslog/syslog_test.go +++ b/daemon/logger/syslog/syslog_test.go @@ -19,6 +19,12 @@ func TestParseLogFormat(t *testing.T) { t.Fatal("Failed to parse rfc5424 format", err, formatter, framer) } + formatter, framer, err = parseLogFormat("rfc5424micro") + if err != nil || !functionMatches(rfc5424microformatterWithAppNameAsTag, formatter) || + !functionMatches(syslog.RFC5425MessageLengthFramer, framer) { + t.Fatal("Failed to parse rfc5424 (microsecond) format", err, formatter, framer) + } + formatter, framer, err = parseLogFormat("rfc3164") if err != nil || !functionMatches(syslog.RFC3164Formatter, formatter) || !functionMatches(syslog.DefaultFramer, framer) { diff --git a/docs/admin/logging/overview.md b/docs/admin/logging/overview.md index 8a7cd12ffb..c3c6e15f8e 100644 --- a/docs/admin/logging/overview.md +++ b/docs/admin/logging/overview.md @@ -80,7 +80,7 @@ The following logging options are supported for the `syslog` logging driver: --log-opt syslog-tls-key=/etc/ca-certificates/custom/key.pem --log-opt syslog-tls-skip-verify=true --log-opt tag="mailer" - --log-opt syslog-format=[rfc5424|rfc3164] + --log-opt syslog-format=[rfc5424|rfc5424micro|rfc3164] `syslog-address` specifies the remote syslog server address where the driver connects to. If not specified it defaults to the local unix socket of the running system. @@ -135,7 +135,8 @@ the log tag format. `syslog-format` specifies syslog message format to use when logging. If not specified it defaults to the local unix syslog format without hostname specification. Specify rfc3164 to perform logging in RFC-3164 compatible format. Specify rfc5424 to perform -logging in RFC-5424 compatible format +logging in RFC-5424 compatible format. Specify rfc5424micro to perform logging in RFC-5424 +compatible format with microsecond timestamp resolution. ## journald options