diff --git a/components/engine/daemon/logger/gelf/gelf.go b/components/engine/daemon/logger/gelf/gelf.go index 5d36252130..a03e6199e0 100644 --- a/components/engine/daemon/logger/gelf/gelf.go +++ b/components/engine/daemon/logger/gelf/gelf.go @@ -47,6 +47,10 @@ func New(info logger.Info) (logger.Logger, error) { return nil, err } + if address.Scheme == "tcp" { + return nil, fmt.Errorf("gelf: TCP not yet implemented") + } + // collect extra data for GELF message hostname, err := info.Hostname() if err != nil { @@ -90,9 +94,9 @@ func New(info logger.Info) (logger.Logger, error) { } // create new gelfWriter - gelfWriter, err := gelf.NewUDPWriter(address) + gelfWriter, err := gelf.NewUDPWriter(address.String()) if err != nil { - return nil, fmt.Errorf("gelf: cannot connect to GELF endpoint: %s %v", address, err) + return nil, fmt.Errorf("gelf: cannot connect to GELF endpoint: %s %v", address.String(), err) } if v, ok := info.Config["gelf-compression-type"]; ok { @@ -156,6 +160,11 @@ func (s *gelfLogger) Name() string { // ValidateLogOpt looks for gelf specific log option gelf-address. func ValidateLogOpt(cfg map[string]string) error { + address, err := parseAddress(cfg["gelf-address"]) + if err != nil { + return err + } + for key, val := range cfg { switch key { case "gelf-address": @@ -164,46 +173,59 @@ func ValidateLogOpt(cfg map[string]string) error { case "env": case "env-regex": case "gelf-compression-level": + if address.Scheme != "udp" { + return fmt.Errorf("compression is only supported on UDP") + } i, err := strconv.Atoi(val) if err != nil || i < flate.DefaultCompression || i > flate.BestCompression { return fmt.Errorf("unknown value %q for log opt %q for gelf log driver", val, key) } case "gelf-compression-type": + if address.Scheme != "udp" { + return fmt.Errorf("compression is only supported on UDP") + } switch val { case "gzip", "zlib", "none": default: return fmt.Errorf("unknown value %q for log opt %q for gelf log driver", val, key) } + case "gelf-tcp-max-reconnect", "gelf-tcp-reconnect-delay": + if address.Scheme != "tcp" { + return fmt.Errorf("%q is only valid for TCP", key) + } + i, err := strconv.Atoi(val) + if err != nil || i < 0 { + return fmt.Errorf("%q must be a positive integer", key) + } default: return fmt.Errorf("unknown log opt %q for gelf log driver", key) } } - _, err := parseAddress(cfg["gelf-address"]) - return err + return nil } -func parseAddress(address string) (string, error) { +func parseAddress(address string) (*url.URL, error) { if address == "" { - return "", nil + return nil, fmt.Errorf("gelf-address is a required parameter") } if !urlutil.IsTransportURL(address) { - return "", fmt.Errorf("gelf-address should be in form proto://address, got %v", address) + return nil, fmt.Errorf("gelf-address should be in form proto://address, got %v", address) } url, err := url.Parse(address) if err != nil { - return "", err + return nil, err } // we support only udp - if url.Scheme != "udp" { - return "", fmt.Errorf("gelf: endpoint needs to be UDP") + if url.Scheme != "udp" && url.Scheme != "tcp" { + return nil, fmt.Errorf("gelf: endpoint needs to be TCP or UDP") } // get host and port if _, _, err = net.SplitHostPort(url.Host); err != nil { - return "", fmt.Errorf("gelf: please provide gelf-address as udp://host:port") + return nil, fmt.Errorf("gelf: please provide gelf-address as proto://host:port") } - return url.Host, nil + return url, nil } diff --git a/components/engine/daemon/logger/gelf/gelf_test.go b/components/engine/daemon/logger/gelf/gelf_test.go index dd83427107..d47bea531f 100644 --- a/components/engine/daemon/logger/gelf/gelf_test.go +++ b/components/engine/daemon/logger/gelf/gelf_test.go @@ -8,12 +8,12 @@ import ( //Validate parseAddress func TestParseAddress(t *testing.T) { - host, err := parseAddress("udp://127.0.0.1:12201") + url, err := parseAddress("udp://127.0.0.1:12201") if err != nil { t.Fatal(err) } - if host != "127.0.0.1:12201" { - t.Fatalf("Expected host 127.0.0.1, got %s", host) + if url.String() != "udp://127.0.0.1:12201" { + t.Fatalf("Expected address udp://127.0.0.1:12201, got %s", url.String()) } _, err = parseAddress("127.0.0.1:12201") @@ -27,8 +27,8 @@ func TestParseAddress(t *testing.T) { } } -//Validate options -func TestValidateLogOpt(t *testing.T) { +//Validate UDP options +func TestUDPValidateLogOpt(t *testing.T) { err := ValidateLogOpt(map[string]string{ "gelf-address": "udp://127.0.0.1:12201", "tag": "testtag", @@ -65,4 +65,71 @@ func TestValidateLogOpt(t *testing.T) { if err == nil { t.Fatal("Expected unknown option error") } + + err = ValidateLogOpt(map[string]string{}) + if err == nil { + t.Fatal("Expected required parameter error") + } +} + +//Validate TCP options +func TestTCPValidateLogOpt(t *testing.T) { + err := ValidateLogOpt(map[string]string{ + "gelf-address": "tcp://127.0.0.1:12201", + }) + if err != nil { + t.Fatal("Expected TCP to be supported") + } + + err = ValidateLogOpt(map[string]string{ + "gelf-address": "tcp://127.0.0.1:12201", + "gelf-compression-level": "9", + }) + if err == nil { + t.Fatal("Expected TCP to reject compression level") + } + + err = ValidateLogOpt(map[string]string{ + "gelf-address": "tcp://127.0.0.1:12201", + "gelf-compression-type": "gzip", + }) + if err == nil { + t.Fatal("Expected TCP to reject compression type") + } + + err = ValidateLogOpt(map[string]string{ + "gelf-address": "tcp://127.0.0.1:12201", + "gelf-tcp-max-reconnect": "5", + "gelf-tcp-reconnect-delay": "10", + }) + if err != nil { + t.Fatal("Expected TCP reconnect to be a valid parameters") + } + + err = ValidateLogOpt(map[string]string{ + "gelf-address": "tcp://127.0.0.1:12201", + "gelf-tcp-max-reconnect": "-1", + "gelf-tcp-reconnect-delay": "-3", + }) + if err == nil { + t.Fatal("Expected negative TCP reconnect to be rejected") + } + + err = ValidateLogOpt(map[string]string{ + "gelf-address": "tcp://127.0.0.1:12201", + "gelf-tcp-max-reconnect": "invalid", + "gelf-tcp-reconnect-delay": "invalid", + }) + if err == nil { + t.Fatal("Expected TCP reconnect to be required to be an int") + } + + err = ValidateLogOpt(map[string]string{ + "gelf-address": "udp://127.0.0.1:12201", + "gelf-tcp-max-reconnect": "1", + "gelf-tcp-reconnect-delay": "3", + }) + if err == nil { + t.Fatal("Expected TCP reconnect to be invalid for UDP") + } }