From 9528ea930cdb90f906230a6d4cab179001255927 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sat, 18 Jun 2016 21:30:33 -0700 Subject: [PATCH] Sanitize docker labels when used as journald field names This fix tries to address the issue raised in #23528 where docker labels caused journald log error because journald has special requirements on field names. This fix addresses this issue by sanitize the labels per requirements of journald. Additional unit tests have been added to cover the changes. This fix fixes #23528. Signed-off-by: Yong Tang --- daemon/logger/journald/journald.go | 24 ++++++++++++++++++++++-- daemon/logger/journald/journald_test.go | 23 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 daemon/logger/journald/journald_test.go diff --git a/daemon/logger/journald/journald.go b/daemon/logger/journald/journald.go index 5e288eaaf7..9569859121 100644 --- a/daemon/logger/journald/journald.go +++ b/daemon/logger/journald/journald.go @@ -6,8 +6,8 @@ package journald import ( "fmt" - "strings" "sync" + "unicode" "github.com/Sirupsen/logrus" "github.com/coreos/go-systemd/journal" @@ -36,6 +36,26 @@ func init() { } } +// sanitizeKeyMode returns the sanitized string so that it could be used in journald. +// In journald log, there are special requirements for fields. +// Fields must be composed of uppercase letters, numbers, and underscores, but must +// not start with an underscore. +func sanitizeKeyMod(s string) string { + n := "" + for _, v := range s { + if 'a' <= v && v <= 'z' { + v = unicode.ToUpper(v) + } else if ('Z' < v || v < 'A') && ('9' < v || v < '0') { + v = '_' + } + // If (n == "" && v == '_'), then we will skip as this is the beginning with '_' + if !(n == "" && v == '_') { + n += string(v) + } + } + return n +} + // New creates a journald logger using the configuration passed in on // the context. func New(ctx logger.Context) (logger.Logger, error) { @@ -61,7 +81,7 @@ func New(ctx logger.Context) (logger.Logger, error) { "CONTAINER_NAME": name, "CONTAINER_TAG": tag, } - extraAttrs := ctx.ExtraAttributes(strings.ToTitle) + extraAttrs := ctx.ExtraAttributes(sanitizeKeyMod) for k, v := range extraAttrs { vars[k] = v } diff --git a/daemon/logger/journald/journald_test.go b/daemon/logger/journald/journald_test.go new file mode 100644 index 0000000000..224423fd07 --- /dev/null +++ b/daemon/logger/journald/journald_test.go @@ -0,0 +1,23 @@ +// +build linux + +package journald + +import ( + "testing" +) + +func TestSanitizeKeyMod(t *testing.T) { + entries := map[string]string{ + "io.kubernetes.pod.name": "IO_KUBERNETES_POD_NAME", + "io?.kubernetes.pod.name": "IO__KUBERNETES_POD_NAME", + "?io.kubernetes.pod.name": "IO_KUBERNETES_POD_NAME", + "io123.kubernetes.pod.name": "IO123_KUBERNETES_POD_NAME", + "_io123.kubernetes.pod.name": "IO123_KUBERNETES_POD_NAME", + "__io123_kubernetes.pod.name": "IO123_KUBERNETES_POD_NAME", + } + for k, v := range entries { + if sanitizeKeyMod(k) != v { + t.Fatalf("Failed to sanitize %s, got %s, expected %s", k, sanitizeKeyMod(k), v) + } + } +}