Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1a40dd5

Browse files
committed
Fixes moby#18712. Add rfc5424 log format for syslog.
Previously docker used obsolete rfc3164 syslog format for syslog. rfc3164 explicitly uses semicolon as a separator between 'TAG' and 'Content' section of the log message. Docker uses semicolon as a separator between image name and version tag. When {{.ImageName}} was used as a tag expression and contained ":" syslog parser mistreated "tag" part of the image name as syslog message body, which resulted in incorrect "syslogtag" been reported by syslog daemon. Use of rfc5424 log format partually fixes the issue as it does not use semicolon as a separator. However using default rfc5424 syslog format itroduces backward incompatability because rsyslog template keyword %syslogtag% is parsed differently. In rfc3164 it uses the "TAG" part reported before the "pid" part. In rfc5424 it uses "appname" part reported before the pid part, while tag part is introduced by %msgid% part. For more information on rsyslog configuration properties see: http://www.rsyslog.com/doc/master/configuration/properties.html Added two options to specify logging in either rfc5424, rfc3164 format or unix format omitting hostname in order to keep backwards compatability with previous versions. Signed-off-by: Solganik Alexander <[email protected]>
1 parent f988741 commit 1a40dd5

3 files changed

Lines changed: 89 additions & 0 deletions

File tree

daemon/logger/syslog/syslog.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"path"
1414
"strconv"
1515
"strings"
16+
"time"
1617

1718
syslog "github.com/RackSec/srslog"
1819

@@ -64,6 +65,17 @@ func init() {
6465
}
6566
}
6667

68+
// rsyslog uses appname part of syslog message to fill in an %syslogtag% template
69+
// attribute in rsyslog.conf. In order to be backward compatible to rfc3164
70+
// tag will be also used as an appname
71+
func rfc5424formatterWithAppNameAsTag(p syslog.Priority, hostname, tag, content string) string {
72+
timestamp := time.Now().Format(time.RFC3339)
73+
pid := os.Getpid()
74+
msg := fmt.Sprintf("<%d>%d %s %s %s %d %s %s",
75+
p, 1, timestamp, hostname, tag, pid, tag, content)
76+
return msg
77+
}
78+
6779
// New creates a syslog logger using the configuration passed in on
6880
// the context. Supported context configuration variables are
6981
// syslog-address, syslog-facility, & syslog-tag.
@@ -83,6 +95,11 @@ func New(ctx logger.Context) (logger.Logger, error) {
8395
return nil, err
8496
}
8597

98+
syslogFormatter, syslogFramer, err := parseLogFormat(ctx.Config["syslog-format"])
99+
if err != nil {
100+
return nil, err
101+
}
102+
86103
logTag := path.Base(os.Args[0]) + "/" + tag
87104

88105
var log *syslog.Writer
@@ -100,6 +117,9 @@ func New(ctx logger.Context) (logger.Logger, error) {
100117
return nil, err
101118
}
102119

120+
log.SetFormatter(syslogFormatter)
121+
log.SetFramer(syslogFramer)
122+
103123
return &syslogger{
104124
writer: log,
105125
}, nil
@@ -165,6 +185,7 @@ func ValidateLogOpt(cfg map[string]string) error {
165185
case "syslog-tls-key":
166186
case "syslog-tls-skip-verify":
167187
case "tag":
188+
case "syslog-format":
168189
default:
169190
return fmt.Errorf("unknown log opt '%s' for syslog log driver", key)
170191
}
@@ -175,6 +196,9 @@ func ValidateLogOpt(cfg map[string]string) error {
175196
if _, err := parseFacility(cfg["syslog-facility"]); err != nil {
176197
return err
177198
}
199+
if _, _, err := parseLogFormat(cfg["syslog-format"]); err != nil {
200+
return err
201+
}
178202
return nil
179203
}
180204

@@ -207,3 +231,17 @@ func parseTLSConfig(cfg map[string]string) (*tls.Config, error) {
207231

208232
return tlsconfig.Client(opts)
209233
}
234+
235+
func parseLogFormat(logFormat string) (syslog.Formatter, syslog.Framer, error) {
236+
switch logFormat {
237+
case "":
238+
return syslog.UnixFormatter, syslog.DefaultFramer, nil
239+
case "rfc3164":
240+
return syslog.RFC3164Formatter, syslog.DefaultFramer, nil
241+
case "rfc5424":
242+
return rfc5424formatterWithAppNameAsTag, syslog.RFC5425MessageLengthFramer, nil
243+
default:
244+
return nil, nil, errors.New("Invalid syslog format")
245+
}
246+
247+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// +build linux
2+
3+
package syslog
4+
5+
import (
6+
syslog "github.com/RackSec/srslog"
7+
"reflect"
8+
"testing"
9+
)
10+
11+
func functionMatches(expectedFun interface{}, actualFun interface{}) bool {
12+
return reflect.ValueOf(expectedFun).Pointer() == reflect.ValueOf(actualFun).Pointer()
13+
}
14+
15+
func TestParseLogFormat(t *testing.T) {
16+
formatter, framer, err := parseLogFormat("rfc5424")
17+
if err != nil || !functionMatches(rfc5424formatterWithAppNameAsTag, formatter) ||
18+
!functionMatches(syslog.RFC5425MessageLengthFramer, framer) {
19+
t.Fatal("Failed to parse rfc5424 format", err, formatter, framer)
20+
}
21+
22+
formatter, framer, err = parseLogFormat("rfc3164")
23+
if err != nil || !functionMatches(syslog.RFC3164Formatter, formatter) ||
24+
!functionMatches(syslog.DefaultFramer, framer) {
25+
t.Fatal("Failed to parse rfc3164 format", err, formatter, framer)
26+
}
27+
28+
formatter, framer, err = parseLogFormat("")
29+
if err != nil || !functionMatches(syslog.UnixFormatter, formatter) ||
30+
!functionMatches(syslog.DefaultFramer, framer) {
31+
t.Fatal("Failed to parse empty format", err, formatter, framer)
32+
}
33+
34+
formatter, framer, err = parseLogFormat("invalid")
35+
if err == nil {
36+
t.Fatal("Failed to parse invalid format", err, formatter, framer)
37+
}
38+
}
39+
40+
func TestValidateLogOptEmpty(t *testing.T) {
41+
emptyConfig := make(map[string]string)
42+
if err := ValidateLogOpt(emptyConfig); err != nil {
43+
t.Fatal("Failed to parse empty config", err)
44+
}
45+
}

docs/admin/logging/overview.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ The following logging options are supported for the `syslog` logging driver:
8080
--log-opt syslog-tls-key=/etc/ca-certificates/custom/key.pem
8181
--log-opt syslog-tls-skip-verify=true
8282
--log-opt tag="mailer"
83+
--log-opt syslog-format=[rfc5424|rfc3164]
8384

8485
`syslog-address` specifies the remote syslog server address where the driver connects to.
8586
If not specified it defaults to the local unix socket of the running system.
@@ -131,6 +132,11 @@ By default, Docker uses the first 12 characters of the container ID to tag log m
131132
Refer to the [log tag option documentation](log_tags.md) for customizing
132133
the log tag format.
133134

135+
`syslog-format` specifies syslog message format to use when logging.
136+
If not specified it defaults to the local unix syslog format without hostname specification.
137+
Specify rfc3164 to perform logging in RFC-3164 compatible format. Specify rfc5424 to perform
138+
logging in RFC-5424 compatible format
139+
134140

135141
## journald options
136142

0 commit comments

Comments
 (0)