1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Use a regex to match environment variables #27565

Signed-off-by: Joseph Rothrock <rothrock@rothrock.org>
This commit is contained in:
Joseph Rothrock 2016-11-08 16:34:47 -08:00
parent e1c5e72902
commit 9758a2a724
11 changed files with 89 additions and 34 deletions

View file

@ -78,7 +78,10 @@ func New(info logger.Info) (logger.Logger, error) {
return nil, err return nil, err
} }
extra := info.ExtraAttributes(nil) extra, err := info.ExtraAttributes(nil)
if err != nil {
return nil, err
}
bufferLimit := defaultBufferLimit bufferLimit := defaultBufferLimit
if info.Config[bufferLimitKey] != "" { if info.Config[bufferLimitKey] != "" {
@ -169,6 +172,7 @@ func ValidateLogOpt(cfg map[string]string) error {
for key := range cfg { for key := range cfg {
switch key { switch key {
case "env": case "env":
case "env-regex":
case "labels": case "labels":
case "tag": case "tag":
case addressKey: case addressKey:

View file

@ -20,6 +20,7 @@ const (
projectOptKey = "gcp-project" projectOptKey = "gcp-project"
logLabelsKey = "labels" logLabelsKey = "labels"
logEnvKey = "env" logEnvKey = "env"
logEnvRegexKey = "env-regex"
logCmdKey = "gcp-log-cmd" logCmdKey = "gcp-log-cmd"
logZoneKey = "gcp-meta-zone" logZoneKey = "gcp-meta-zone"
logNameKey = "gcp-meta-name" logNameKey = "gcp-meta-name"
@ -133,6 +134,11 @@ func New(info logger.Info) (logger.Logger, error) {
return nil, fmt.Errorf("unable to connect or authenticate with Google Cloud Logging: %v", err) return nil, fmt.Errorf("unable to connect or authenticate with Google Cloud Logging: %v", err)
} }
extraAttributes, err := info.ExtraAttributes(nil)
if err != nil {
return nil, err
}
l := &gcplogs{ l := &gcplogs{
logger: lg, logger: lg,
container: &containerInfo{ container: &containerInfo{
@ -141,7 +147,7 @@ func New(info logger.Info) (logger.Logger, error) {
ImageName: info.ContainerImageName, ImageName: info.ContainerImageName,
ImageID: info.ContainerImageID, ImageID: info.ContainerImageID,
Created: info.ContainerCreated, Created: info.ContainerCreated,
Metadata: info.ExtraAttributes(nil), Metadata: extraAttributes,
}, },
} }
@ -185,7 +191,7 @@ func New(info logger.Info) (logger.Logger, error) {
func ValidateLogOpts(cfg map[string]string) error { func ValidateLogOpts(cfg map[string]string) error {
for k := range cfg { for k := range cfg {
switch k { switch k {
case projectOptKey, logLabelsKey, logEnvKey, logCmdKey, logZoneKey, logNameKey, logIDKey: case projectOptKey, logLabelsKey, logEnvKey, logEnvRegexKey, logCmdKey, logZoneKey, logNameKey, logIDKey:
default: default:
return fmt.Errorf("%q is not a valid option for the gcplogs driver", k) return fmt.Errorf("%q is not a valid option for the gcplogs driver", k)
} }

View file

@ -69,12 +69,17 @@ func New(info logger.Info) (logger.Logger, error) {
"_created": info.ContainerCreated, "_created": info.ContainerCreated,
} }
extraAttrs := info.ExtraAttributes(func(key string) string { extraAttrs, err := info.ExtraAttributes(func(key string) string {
if key[0] == '_' { if key[0] == '_' {
return key return key
} }
return "_" + key return "_" + key
}) })
if err != nil {
return nil, err
}
for k, v := range extraAttrs { for k, v := range extraAttrs {
extra[k] = v extra[k] = v
} }
@ -156,6 +161,7 @@ func ValidateLogOpt(cfg map[string]string) error {
case "tag": case "tag":
case "labels": case "labels":
case "env": case "env":
case "env-regex":
case "gelf-compression-level": case "gelf-compression-level":
i, err := strconv.Atoi(val) i, err := strconv.Atoi(val)
if err != nil || i < flate.DefaultCompression || i > flate.BestCompression { if err != nil || i < flate.DefaultCompression || i > flate.BestCompression {

View file

@ -75,7 +75,10 @@ func New(info logger.Info) (logger.Logger, error) {
"CONTAINER_NAME": info.Name(), "CONTAINER_NAME": info.Name(),
"CONTAINER_TAG": tag, "CONTAINER_TAG": tag,
} }
extraAttrs := info.ExtraAttributes(sanitizeKeyMod) extraAttrs, err := info.ExtraAttributes(sanitizeKeyMod)
if err != nil {
return nil, err
}
for k, v := range extraAttrs { for k, v := range extraAttrs {
vars[k] = v vars[k] = v
} }
@ -89,6 +92,7 @@ func validateLogOpt(cfg map[string]string) error {
switch key { switch key {
case "labels": case "labels":
case "env": case "env":
case "env-regex":
case "tag": case "tag":
default: default:
return fmt.Errorf("unknown log opt '%s' for journald log driver", key) return fmt.Errorf("unknown log opt '%s' for journald log driver", key)

View file

@ -67,7 +67,11 @@ func New(info logger.Info) (logger.Logger, error) {
} }
var extra []byte var extra []byte
if attrs := info.ExtraAttributes(nil); len(attrs) > 0 { attrs, err := info.ExtraAttributes(nil)
if err != nil {
return nil, err
}
if len(attrs) > 0 {
var err error var err error
extra, err = json.Marshal(attrs) extra, err = json.Marshal(attrs)
if err != nil { if err != nil {
@ -121,6 +125,7 @@ func ValidateLogOpt(cfg map[string]string) error {
case "max-size": case "max-size":
case "labels": case "labels":
case "env": case "env":
case "env-regex":
default: default:
return fmt.Errorf("unknown log opt '%s' for json-file log driver", key) return fmt.Errorf("unknown log opt '%s' for json-file log driver", key)
} }

View file

@ -160,13 +160,13 @@ func TestJSONFileLoggerWithLabelsEnv(t *testing.T) {
} }
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
filename := filepath.Join(tmp, "container.log") filename := filepath.Join(tmp, "container.log")
config := map[string]string{"labels": "rack,dc", "env": "environ,debug,ssl"} config := map[string]string{"labels": "rack,dc", "env": "environ,debug,ssl", "env-regex": "^dc"}
l, err := New(logger.Info{ l, err := New(logger.Info{
ContainerID: cid, ContainerID: cid,
LogPath: filename, LogPath: filename,
Config: config, Config: config,
ContainerLabels: map[string]string{"rack": "101", "dc": "lhr"}, ContainerLabels: map[string]string{"rack": "101", "dc": "lhr"},
ContainerEnv: []string{"environ=production", "debug=false", "port=10001", "ssl=true"}, ContainerEnv: []string{"environ=production", "debug=false", "port=10001", "ssl=true", "dc_region=west"},
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -194,6 +194,7 @@ func TestJSONFileLoggerWithLabelsEnv(t *testing.T) {
"environ": "production", "environ": "production",
"debug": "false", "debug": "false",
"ssl": "true", "ssl": "true",
"dc_region": "west",
} }
if !reflect.DeepEqual(extra, expected) { if !reflect.DeepEqual(extra, expected) {
t.Fatalf("Wrong log attrs: %q, expected %q", extra, expected) t.Fatalf("Wrong log attrs: %q, expected %q", extra, expected)

View file

@ -78,6 +78,7 @@ func ValidateLogOpt(cfg map[string]string) error {
for key := range cfg { for key := range cfg {
switch key { switch key {
case "env": case "env":
case "env-regex":
case "labels": case "labels":
case "tag": case "tag":
case key: case key:

View file

@ -3,6 +3,7 @@ package logger
import ( import (
"fmt" "fmt"
"os" "os"
"regexp"
"strings" "strings"
"time" "time"
) )
@ -26,7 +27,7 @@ type Info struct {
// ExtraAttributes returns the user-defined extra attributes (labels, // ExtraAttributes returns the user-defined extra attributes (labels,
// environment variables) in key-value format. This can be used by log drivers // environment variables) in key-value format. This can be used by log drivers
// that support metadata to add more context to a log. // that support metadata to add more context to a log.
func (info *Info) ExtraAttributes(keyMod func(string) string) map[string]string { func (info *Info) ExtraAttributes(keyMod func(string) string) (map[string]string, error) {
extra := make(map[string]string) extra := make(map[string]string)
labels, ok := info.Config["labels"] labels, ok := info.Config["labels"]
if ok && len(labels) > 0 { if ok && len(labels) > 0 {
@ -40,14 +41,15 @@ func (info *Info) ExtraAttributes(keyMod func(string) string) map[string]string
} }
} }
env, ok := info.Config["env"]
if ok && len(env) > 0 {
envMapping := make(map[string]string) envMapping := make(map[string]string)
for _, e := range info.ContainerEnv { for _, e := range info.ContainerEnv {
if kv := strings.SplitN(e, "=", 2); len(kv) == 2 { if kv := strings.SplitN(e, "=", 2); len(kv) == 2 {
envMapping[kv[0]] = kv[1] envMapping[kv[0]] = kv[1]
} }
} }
env, ok := info.Config["env"]
if ok && len(env) > 0 {
for _, l := range strings.Split(env, ",") { for _, l := range strings.Split(env, ",") {
if v, ok := envMapping[l]; ok { if v, ok := envMapping[l]; ok {
if keyMod != nil { if keyMod != nil {
@ -58,7 +60,23 @@ func (info *Info) ExtraAttributes(keyMod func(string) string) map[string]string
} }
} }
return extra envRegex, ok := info.Config["env-regex"]
if ok && len(envRegex) > 0 {
re, err := regexp.Compile(envRegex)
if err != nil {
return nil, err
}
for k, v := range envMapping {
if re.MatchString(k) {
if keyMod != nil {
k = keyMod(k)
}
extra[k] = v
}
}
}
return extra, nil
} }
// Hostname returns the hostname from the underlying OS. // Hostname returns the hostname from the underlying OS.

View file

@ -39,6 +39,7 @@ const (
splunkGzipCompressionKey = "splunk-gzip" splunkGzipCompressionKey = "splunk-gzip"
splunkGzipCompressionLevelKey = "splunk-gzip-level" splunkGzipCompressionLevelKey = "splunk-gzip-level"
envKey = "env" envKey = "env"
envRegexKey = "env-regex"
labelsKey = "labels" labelsKey = "labels"
tagKey = "tag" tagKey = "tag"
) )
@ -235,7 +236,10 @@ func New(info logger.Info) (logger.Logger, error) {
} }
} }
attrs := info.ExtraAttributes(nil) attrs, err := info.ExtraAttributes(nil)
if err != nil {
return nil, err
}
var ( var (
postMessagesFrequency = getAdvancedOptionDuration(envVarPostMessagesFrequency, defaultPostMessagesFrequency) postMessagesFrequency = getAdvancedOptionDuration(envVarPostMessagesFrequency, defaultPostMessagesFrequency)
@ -538,6 +542,7 @@ func ValidateLogOpt(cfg map[string]string) error {
case splunkGzipCompressionKey: case splunkGzipCompressionKey:
case splunkGzipCompressionLevelKey: case splunkGzipCompressionLevelKey:
case envKey: case envKey:
case envRegexKey:
case labelsKey: case labelsKey:
case tagKey: case tagKey:
default: default:

View file

@ -26,6 +26,7 @@ func TestValidateLogOpt(t *testing.T) {
splunkGzipCompressionKey: "true", splunkGzipCompressionKey: "true",
splunkGzipCompressionLevelKey: "1", splunkGzipCompressionLevelKey: "1",
envKey: "a", envKey: "a",
envRegexKey: "^foo",
labelsKey: "b", labelsKey: "b",
tagKey: "c", tagKey: "c",
}) })
@ -217,6 +218,7 @@ func TestInlineFormatWithNonDefaultOptions(t *testing.T) {
splunkGzipCompressionKey: "true", splunkGzipCompressionKey: "true",
tagKey: "{{.ImageName}}/{{.Name}}", tagKey: "{{.ImageName}}/{{.Name}}",
labelsKey: "a", labelsKey: "a",
envRegexKey: "^foo",
}, },
ContainerID: "containeriid", ContainerID: "containeriid",
ContainerName: "/container_name", ContainerName: "/container_name",
@ -225,6 +227,7 @@ func TestInlineFormatWithNonDefaultOptions(t *testing.T) {
ContainerLabels: map[string]string{ ContainerLabels: map[string]string{
"a": "b", "a": "b",
}, },
ContainerEnv: []string{"foo_finder=bar"},
} }
hostname, err := info.Hostname() hostname, err := info.Hostname()
@ -295,6 +298,7 @@ func TestInlineFormatWithNonDefaultOptions(t *testing.T) {
event["source"] != "stdout" || event["source"] != "stdout" ||
event["tag"] != "container_image_name/container_name" || event["tag"] != "container_image_name/container_name" ||
event["attrs"].(map[string]interface{})["a"] != "b" || event["attrs"].(map[string]interface{})["a"] != "b" ||
event["attrs"].(map[string]interface{})["foo_finder"] != "bar" ||
len(event) != 4 { len(event) != 4 {
t.Fatalf("Unexpected event in message %v", event) t.Fatalf("Unexpected event in message %v", event)
} }

View file

@ -184,6 +184,7 @@ func ValidateLogOpt(cfg map[string]string) error {
for key := range cfg { for key := range cfg {
switch key { switch key {
case "env": case "env":
case "env-regex":
case "labels": case "labels":
case "syslog-address": case "syslog-address":
case "syslog-facility": case "syslog-facility":