diff --git a/src/cmd/syslog-agent/app/syslog_agent.go b/src/cmd/syslog-agent/app/syslog_agent.go index 277bbdeb1..48b11e0f7 100644 --- a/src/cmd/syslog-agent/app/syslog_agent.go +++ b/src/cmd/syslog-agent/app/syslog_agent.go @@ -113,13 +113,13 @@ func NewSyslogAgent( cfg.WarnOnInvalidDrains, l, ) - cupsFetcher = bindings.NewDrainParamParser(cupsFetcher, cfg.DefaultDrainMetadata) + cupsFetcher = bindings.NewDrainParamParser(cupsFetcher, cfg.DefaultDrainMetadata, l) } aggregateFetcher := bindings.NewAggregateDrainFetcher(cfg.AggregateDrainURLs, cacheClient) bindingManager := binding.NewManager( cupsFetcher, - bindings.NewDrainParamParser(aggregateFetcher, cfg.DefaultDrainMetadata), + bindings.NewDrainParamParser(aggregateFetcher, cfg.DefaultDrainMetadata, l), connector, m, cfg.Cache.PollingInterval, diff --git a/src/pkg/egress/syslog/filtering_drain_writer.go b/src/pkg/egress/syslog/filtering_drain_writer.go index db6d56d90..79e136c09 100644 --- a/src/pkg/egress/syslog/filtering_drain_writer.go +++ b/src/pkg/egress/syslog/filtering_drain_writer.go @@ -2,6 +2,7 @@ package syslog import ( "errors" + "strings" "code.cloudfoundry.org/go-loggregator/v10/rpc/loggregator_v2" "code.cloudfoundry.org/loggregator-agent-release/src/pkg/egress" @@ -50,7 +51,12 @@ func (w *FilteringDrainWriter) Write(env *loggregator_v2.Envelope) error { } } if env.GetLog() != nil { - if sendsLogs(w.binding.DrainData) { + sourceType, ok := env.GetTags()["source_type"] + if !ok { + // Default to sending logs if no source_type tag is present + sourceType = "" + } + if sendsLogs(w.binding.DrainData, w.binding.LogFilter, sourceType) { return w.writer.Write(env) } } @@ -63,17 +69,40 @@ func (w *FilteringDrainWriter) Write(env *loggregator_v2.Envelope) error { return nil } -func sendsLogs(drainData DrainData) bool { - switch drainData { - case LOGS: +// shouldIncludeLog determines if a log with the given sourceTypeTag should be forwarded +func shouldIncludeLog(logFilter *LogTypeSet, sourceTypeTag string) bool { + // Empty filter or missing source type means no filtering + if logFilter == nil || sourceTypeTag == "" { return true - case LOGS_AND_METRICS: - return true - case LOGS_NO_EVENTS: + } + + // Find the first "/" to extract prefix + idx := strings.IndexByte(sourceTypeTag, '/') + prefix := sourceTypeTag + if idx != -1 { + prefix = sourceTypeTag[:idx] + } + + // Prefer map lookup over switch for performance + logType := LogType(prefix) + if !logType.IsValid() { + // Unknown log type, default to not filtering return true - default: + } + + return logFilter.Contains(logType) +} + +func sendsLogs(drainData DrainData, logFilter *LogTypeSet, sourceTypeTag string) bool { + if drainData != LOGS && drainData != LOGS_AND_METRICS && drainData != LOGS_NO_EVENTS { return false } + + if shouldIncludeLog(logFilter, sourceTypeTag) { + return true + } + + return false } func sendsMetrics(drainData DrainData) bool { diff --git a/src/pkg/egress/syslog/filtering_drain_writer_test.go b/src/pkg/egress/syslog/filtering_drain_writer_test.go index 020e0b157..561e5b764 100644 --- a/src/pkg/egress/syslog/filtering_drain_writer_test.go +++ b/src/pkg/egress/syslog/filtering_drain_writer_test.go @@ -53,6 +53,143 @@ var _ = Describe("Filtering Drain Writer", func() { _, err := syslog.NewFilteringDrainWriter(binding, &fakeWriter{}) Expect(err).To(HaveOccurred()) }) + + It("sends logs when source_type tag is missing", func() { + binding := syslog.Binding{ + DrainData: syslog.LOGS, + } + fakeWriter := &fakeWriter{} + drainWriter, err := syslog.NewFilteringDrainWriter(binding, fakeWriter) + Expect(err).NotTo(HaveOccurred()) + + envelope := &loggregator_v2.Envelope{ + Message: &loggregator_v2.Envelope_Log{ + Log: &loggregator_v2.Log{ + Payload: []byte("test log"), + }, + }, + Tags: map[string]string{ + // source_type tag is intentionally missing + }, + } + + err = drainWriter.Write(envelope) + + Expect(err).NotTo(HaveOccurred()) + Expect(fakeWriter.received).To(Equal(1)) + }) + + It("filters logs based on include filter - includes only APP logs", func() { + appFilter := syslog.LogTypeSet{syslog.LOG_APP: struct{}{}} + binding := syslog.Binding{ + DrainData: syslog.LOGS, + LogFilter: &appFilter, + } + fakeWriter := &fakeWriter{} + drainWriter, err := syslog.NewFilteringDrainWriter(binding, fakeWriter) + Expect(err).NotTo(HaveOccurred()) + + envelopes := []*loggregator_v2.Envelope{ + { + Message: &loggregator_v2.Envelope_Log{ + Log: &loggregator_v2.Log{Payload: []byte("app log")}, + }, + Tags: map[string]string{"source_type": "APP/PROC/WEB/0"}, + }, + { + Message: &loggregator_v2.Envelope_Log{ + Log: &loggregator_v2.Log{Payload: []byte("rtr log")}, + }, + Tags: map[string]string{"source_type": "RTR/1"}, + }, + { + Message: &loggregator_v2.Envelope_Log{ + Log: &loggregator_v2.Log{Payload: []byte("stg log")}, + }, + Tags: map[string]string{"source_type": "STG/0"}, + }, + } + + for _, envelope := range envelopes { + err = drainWriter.Write(envelope) + Expect(err).NotTo(HaveOccurred()) + } + + // Only APP log should be sent + Expect(fakeWriter.received).To(Equal(1)) + }) + + It("filters logs based on exclude filter - excludes RTR logs", func() { + // Include APP and STG, effectively excluding RTR + includeFilter := syslog.LogTypeSet{ + syslog.LOG_APP: struct{}{}, + syslog.LOG_STG: struct{}{}, + } + binding := syslog.Binding{ + DrainData: syslog.LOGS, + LogFilter: &includeFilter, + } + fakeWriter := &fakeWriter{} + drainWriter, err := syslog.NewFilteringDrainWriter(binding, fakeWriter) + Expect(err).NotTo(HaveOccurred()) + + envelopes := []*loggregator_v2.Envelope{ + { + Message: &loggregator_v2.Envelope_Log{ + Log: &loggregator_v2.Log{Payload: []byte("app log")}, + }, + Tags: map[string]string{"source_type": "APP/PROC/WEB/0"}, + }, + { + Message: &loggregator_v2.Envelope_Log{ + Log: &loggregator_v2.Log{Payload: []byte("rtr log")}, + }, + Tags: map[string]string{"source_type": "RTR/1"}, + }, + { + Message: &loggregator_v2.Envelope_Log{ + Log: &loggregator_v2.Log{Payload: []byte("stg log")}, + }, + Tags: map[string]string{"source_type": "STG/0"}, + }, + } + + for _, envelope := range envelopes { + err = drainWriter.Write(envelope) + Expect(err).NotTo(HaveOccurred()) + } + + // APP and STG logs should be sent, RTR should be filtered out + Expect(fakeWriter.received).To(Equal(2)) + }) + + It("sends logs with unknown source_type prefix when filter is set", func() { + appFilter := syslog.LogTypeSet{syslog.LOG_APP: struct{}{}} + binding := syslog.Binding{ + DrainData: syslog.LOGS, + LogFilter: &appFilter, + } + fakeWriter := &fakeWriter{} + drainWriter, err := syslog.NewFilteringDrainWriter(binding, fakeWriter) + Expect(err).NotTo(HaveOccurred()) + + envelope := &loggregator_v2.Envelope{ + Message: &loggregator_v2.Envelope_Log{ + Log: &loggregator_v2.Log{ + Payload: []byte("test log"), + }, + }, + Tags: map[string]string{ + "source_type": "UNKNOWN/some/path", + }, + } + + err = drainWriter.Write(envelope) + + // Should send the log because unknown types default to being included + Expect(err).NotTo(HaveOccurred()) + Expect(fakeWriter.received).To(Equal(1)) + }) }) type fakeWriter struct { diff --git a/src/pkg/egress/syslog/log.go b/src/pkg/egress/syslog/log.go new file mode 100644 index 000000000..1e0338da1 --- /dev/null +++ b/src/pkg/egress/syslog/log.go @@ -0,0 +1,55 @@ +package syslog + +// LogType defines the log types used within Cloud Foundry +// Their order in the code is as documented in https://docs.cloudfoundry.org/devguide/deploy-apps/streaming-logs.html#format +type LogType string + +const ( + LOG_API LogType = "API" + LOG_STG LogType = "STG" + LOG_RTR LogType = "RTR" + LOG_LGR LogType = "LGR" + LOG_APP LogType = "APP" + LOG_SSH LogType = "SSH" + LOG_CELL LogType = "CELL" +) + +// validLogTypes contains LogType prefixes for efficient lookup +var validLogTypes = map[LogType]struct{}{ + LOG_API: {}, + LOG_STG: {}, + LOG_RTR: {}, + LOG_LGR: {}, + LOG_APP: {}, + LOG_SSH: {}, + LOG_CELL: {}, +} + +// IsValid checks if the provided LogType is valid +func (lt LogType) IsValid() bool { + _, ok := validLogTypes[lt] + return ok +} + +// AllLogTypes returns all valid log types +func AllLogTypes() []LogType { + types := make([]LogType, 0, len(validLogTypes)) + for t := range validLogTypes { + types = append(types, t) + } + return types +} + +// LogTypeSet is a set of LogTypes for efficient membership checking +type LogTypeSet map[LogType]struct{} + +// Add adds a LogType to the set +func (s LogTypeSet) Add(lt LogType) { + s[lt] = struct{}{} +} + +// Contains checks if the set contains a LogType +func (s LogTypeSet) Contains(lt LogType) bool { + _, exists := s[lt] + return exists +} diff --git a/src/pkg/egress/syslog/syslog_connector.go b/src/pkg/egress/syslog/syslog_connector.go index de9727d02..6a3f8cfa2 100644 --- a/src/pkg/egress/syslog/syslog_connector.go +++ b/src/pkg/egress/syslog/syslog_connector.go @@ -20,6 +20,7 @@ type Binding struct { DrainData DrainData `json:"type,omitempty"` OmitMetadata bool InternalTls bool + LogFilter *LogTypeSet } type Drain struct { diff --git a/src/pkg/ingress/bindings/binding_config.go b/src/pkg/ingress/bindings/binding_config.go index 9a1931916..dc5b480cf 100644 --- a/src/pkg/ingress/bindings/binding_config.go +++ b/src/pkg/ingress/bindings/binding_config.go @@ -1,7 +1,10 @@ package bindings import ( + "errors" + "log" "net/url" + "strings" "code.cloudfoundry.org/loggregator-agent-release/src/pkg/binding" "code.cloudfoundry.org/loggregator-agent-release/src/pkg/egress/syslog" @@ -10,12 +13,14 @@ import ( type DrainParamParser struct { fetcher binding.Fetcher defaultDrainMetadata bool + log *log.Logger } -func NewDrainParamParser(f binding.Fetcher, defaultDrainMetadata bool) *DrainParamParser { +func NewDrainParamParser(f binding.Fetcher, defaultDrainMetadata bool, l *log.Logger) *DrainParamParser { return &DrainParamParser{ fetcher: f, defaultDrainMetadata: defaultDrainMetadata, + log: l, } } @@ -35,6 +40,10 @@ func (d *DrainParamParser) FetchBindings() ([]syslog.Binding, error) { b.OmitMetadata = getOmitMetadata(urlParsed, d.defaultDrainMetadata) b.InternalTls = getInternalTLS(urlParsed) b.DrainData = getBindingType(urlParsed) + b.LogFilter, err = d.getLogFilter(urlParsed) + if err != nil { + return nil, err + } processed = append(processed, b) } @@ -84,6 +93,68 @@ func getBindingType(u *url.URL) syslog.DrainData { return drainData } +// parseLogType parses a string into a LogType value +func parseLogType(s string) (syslog.LogType, bool) { + lt := syslog.LogType(strings.ToUpper(s)) + return lt, lt.IsValid() +} + +// NewLogTypeSet parses a URL query parameter into a Set of LogTypes +func (d *DrainParamParser) NewLogTypeSet(logTypeList string, isExclude bool) *syslog.LogTypeSet { + if logTypeList == "" { + set := make(syslog.LogTypeSet) + return &set + } + + logTypes := strings.Split(logTypeList, ",") + set := make(syslog.LogTypeSet, len(logTypes)) + var unknownTypes []string + + for _, logType := range logTypes { + logType = strings.TrimSpace(logType) + t, ok := parseLogType(logType) + if !ok { + unknownTypes = append(unknownTypes, logType) + continue + } + set.Add(t) + } + + if len(unknownTypes) > 0 { + d.log.Printf("Unknown log types '%s' in log type filter, ignoring", strings.Join(unknownTypes, ", ")) + } + + if isExclude { + // Invert the set - include all types except those in the set + fullSet := make(syslog.LogTypeSet) + + for _, t := range syslog.AllLogTypes() { + fullSet.Add(t) + } + + for t := range set { + delete(fullSet, t) + } + return &fullSet + } + + return &set +} + +func (d *DrainParamParser) getLogFilter(u *url.URL) (*syslog.LogTypeSet, error) { + includeLogTypes := u.Query().Get("include-log-types") + excludeLogTypes := u.Query().Get("exclude-log-types") + + if excludeLogTypes != "" && includeLogTypes != "" { + return nil, errors.New("include-log-types and exclude-log-types can not be used at the same time") + } else if excludeLogTypes != "" { + return d.NewLogTypeSet(excludeLogTypes, true), nil + } else if includeLogTypes != "" { + return d.NewLogTypeSet(includeLogTypes, false), nil + } + return d.NewLogTypeSet("", false), nil +} + func getRemoveMetadataQuery(u *url.URL) string { q := u.Query().Get("disable-metadata") if q == "" { diff --git a/src/pkg/ingress/bindings/binding_config_test.go b/src/pkg/ingress/bindings/binding_config_test.go index ef9146e74..1ea09198c 100644 --- a/src/pkg/ingress/bindings/binding_config_test.go +++ b/src/pkg/ingress/bindings/binding_config_test.go @@ -2,6 +2,8 @@ package bindings_test import ( "errors" + "log" + "strings" "code.cloudfoundry.org/loggregator-agent-release/src/pkg/egress/syslog" "code.cloudfoundry.org/loggregator-agent-release/src/pkg/ingress/bindings" @@ -10,14 +12,17 @@ import ( ) var _ = Describe("Drain Param Config", func() { + var ( + logger = log.New(GinkgoWriter, "", 0) + ) It("sets OmitMetadata to false if the drain doesn't contain 'disable-metadata=true'", func() { bs := []syslog.Binding{ {Drain: syslog.Drain{Url: "https://test.org/drain"}}, } f := newStubFetcher(bs, nil) - wf := bindings.NewDrainParamParser(f, true) + dp := bindings.NewDrainParamParser(f, true, logger) - configedBindings, _ := wf.FetchBindings() + configedBindings, _ := dp.FetchBindings() Expect(configedBindings[0].OmitMetadata).To(BeFalse()) }) @@ -27,9 +32,9 @@ var _ = Describe("Drain Param Config", func() { {Drain: syslog.Drain{Url: "https://test.org/drain?omit-metadata=true"}}, } f := newStubFetcher(bs, nil) - wf := bindings.NewDrainParamParser(f, true) + dp := bindings.NewDrainParamParser(f, true, logger) - configedBindings, _ := wf.FetchBindings() + configedBindings, _ := dp.FetchBindings() Expect(configedBindings[0].OmitMetadata).To(BeTrue()) Expect(configedBindings[1].OmitMetadata).To(BeTrue()) }) @@ -39,9 +44,9 @@ var _ = Describe("Drain Param Config", func() { {Drain: syslog.Drain{Url: "https://test.org/drain"}}, } f := newStubFetcher(bs, nil) - wf := bindings.NewDrainParamParser(f, false) + dp := bindings.NewDrainParamParser(f, false, logger) - configedBindings, _ := wf.FetchBindings() + configedBindings, _ := dp.FetchBindings() Expect(configedBindings[0].OmitMetadata).To(BeTrue()) }) @@ -51,9 +56,9 @@ var _ = Describe("Drain Param Config", func() { {Drain: syslog.Drain{Url: "https://test.org/drain?omit-metadata=false"}}, } f := newStubFetcher(bs, nil) - wf := bindings.NewDrainParamParser(f, false) + dp := bindings.NewDrainParamParser(f, false, logger) - configedBindings, _ := wf.FetchBindings() + configedBindings, _ := dp.FetchBindings() Expect(configedBindings[0].OmitMetadata).To(BeFalse()) Expect(configedBindings[1].OmitMetadata).To(BeFalse()) }) @@ -63,48 +68,195 @@ var _ = Describe("Drain Param Config", func() { {Drain: syslog.Drain{Url: "https://test.org/drain?ssl-strict-internal=true"}}, } f := newStubFetcher(bs, nil) - wf := bindings.NewDrainParamParser(f, true) + dp := bindings.NewDrainParamParser(f, true, logger) - configedBindings, _ := wf.FetchBindings() + configedBindings, _ := dp.FetchBindings() Expect(configedBindings[0].InternalTls).To(BeTrue()) }) It("sets drain data appropriately'", func() { + testCases := []struct { + name string + url string + expected syslog.DrainData + }{ + { + name: "no drain-data parameter defaults to logs", + url: "https://test.org/drain", + expected: syslog.LOGS, + }, + { + name: "drain-data=logs", + url: "https://test.org/drain?drain-data=logs", + expected: syslog.LOGS, + }, + { + name: "drain-data=metrics", + url: "https://test.org/drain?drain-data=metrics", + expected: syslog.METRICS, + }, + { + name: "drain-data=traces", + url: "https://test.org/drain?drain-data=traces", + expected: syslog.TRACES, + }, + { + name: "drain-data=all", + url: "https://test.org/drain?drain-data=all", + expected: syslog.ALL, + }, + } + + for _, tc := range testCases { + By(tc.name) + bs := []syslog.Binding{ + {Drain: syslog.Drain{Url: tc.url}}, + } + f := newStubFetcher(bs, nil) + dp := bindings.NewDrainParamParser(f, true, logger) + + configedBindings, _ := dp.FetchBindings() + Expect(configedBindings[0].DrainData).To(Equal(tc.expected)) + } + }) + + It("sets drain filter appropriately", func() { + testCases := []struct { + name string + url string + expected *syslog.LogTypeSet + }{ + { + name: "empty drain URL defaults to all types", + url: "https://test.org/drain", + expected: NewLogTypeSet(), + }, + { + name: "include-log-types=app", + url: "https://test.org/drain?include-log-types=app", + expected: NewLogTypeSet(syslog.LOG_APP), + }, + { + name: "include-log-types=app,stg,cell", + url: "https://test.org/drain?include-log-types=app,stg,cell", + expected: NewLogTypeSet(syslog.LOG_APP, syslog.LOG_STG, syslog.LOG_CELL), + }, + { + name: "exclude-log-types=rtr,cell,stg", + url: "https://test.org/drain?exclude-log-types=rtr,cell,stg", + expected: NewLogTypeSet(syslog.LOG_API, syslog.LOG_LGR, syslog.LOG_APP, syslog.LOG_SSH), + }, + { + name: "exclude-log-types=rtr", + url: "https://test.org/drain?exclude-log-types=rtr", + expected: NewLogTypeSet(syslog.LOG_API, syslog.LOG_STG, syslog.LOG_LGR, syslog.LOG_APP, syslog.LOG_SSH, syslog.LOG_CELL), + }, + } + + for _, tc := range testCases { + By(tc.name) + bs := []syslog.Binding{ + {Drain: syslog.Drain{Url: tc.url}}, + } + f := newStubFetcher(bs, nil) + dp := bindings.NewDrainParamParser(f, true, logger) + + configedBindings, _ := dp.FetchBindings() + Expect(configedBindings[0].LogFilter).To(Equal(tc.expected), "failed for case: %s", tc.name) + } + }) + + It("returns an error when both include-log-types and exclude-log-types are specified", func() { bs := []syslog.Binding{ - {Drain: syslog.Drain{Url: "https://test.org/drain"}}, - {Drain: syslog.Drain{Url: "https://test.org/drain?drain-data=logs"}}, - {Drain: syslog.Drain{Url: "https://test.org/drain?drain-data=metrics"}}, - {Drain: syslog.Drain{Url: "https://test.org/drain?drain-data=traces"}}, - {Drain: syslog.Drain{Url: "https://test.org/drain?drain-data=all"}}, + {Drain: syslog.Drain{Url: "https://test.org/drain?include-log-types=app&exclude-log-types=rtr"}}, } f := newStubFetcher(bs, nil) - wf := bindings.NewDrainParamParser(f, true) - - configedBindings, _ := wf.FetchBindings() - Expect(configedBindings[0].DrainData).To(Equal(syslog.LOGS)) - Expect(configedBindings[1].DrainData).To(Equal(syslog.LOGS)) - Expect(configedBindings[2].DrainData).To(Equal(syslog.METRICS)) - Expect(configedBindings[3].DrainData).To(Equal(syslog.TRACES)) - Expect(configedBindings[4].DrainData).To(Equal(syslog.ALL)) + dp := bindings.NewDrainParamParser(f, true, logger) + + configedBindings, err := dp.FetchBindings() + Expect(err).To(HaveOccurred()) + Expect(configedBindings).To(HaveLen(0)) + }) + + It("logs a single warning when multiple unknown log types are provided", func() { + var logOutput strings.Builder + testLogger := log.New(&logOutput, "", log.LstdFlags) + parser := bindings.NewDrainParamParser(newStubFetcher(nil, nil), false, testLogger) + + result := parser.NewLogTypeSet("app,unknown,invalid,rtr", false) + + // Should only contain APP and RTR, not the unknown type + Expect(result).To(Equal(NewLogTypeSet(syslog.LOG_APP, syslog.LOG_RTR))) + + // Should have logged exactly one warning containing all unknown types + output := logOutput.String() + Expect(output).To(ContainSubstring("unknown")) + Expect(output).To(ContainSubstring("invalid")) + Expect(output).To(ContainSubstring("ignoring")) + + // Verify it's a single log line (only one newline) + Expect(strings.Count(output, "\n")).To(Equal(1)) + }) + + It("handles unknown log types in exclude mode", func() { + var logOutput strings.Builder + testLogger := log.New(&logOutput, "", log.LstdFlags) + parser := bindings.NewDrainParamParser(newStubFetcher(nil, nil), false, testLogger) + + result := parser.NewLogTypeSet("rtr,unknown", true) + + // Should exclude only RTR (unknown type is ignored) + expectedSet := NewLogTypeSet(syslog.LOG_API, syslog.LOG_STG, syslog.LOG_LGR, syslog.LOG_APP, syslog.LOG_SSH, syslog.LOG_CELL) + Expect(result).To(Equal(expectedSet)) + + // Should have logged a warning + Expect(logOutput.String()).To(ContainSubstring("ignoring")) }) It("sets drain data for old parameter appropriately'", func() { - bs := []syslog.Binding{ - {Drain: syslog.Drain{Url: "https://test.org/drain?drain-type=metrics"}}, - {Drain: syslog.Drain{Url: "https://test.org/drain?drain-type=logs"}}, - {Drain: syslog.Drain{Url: "https://test.org/drain"}}, - {Drain: syslog.Drain{Url: "https://test.org/drain?drain-type=all"}}, - {Drain: syslog.Drain{Url: "https://test.org/drain?include-metrics-deprecated=true"}}, + testCases := []struct { + name string + url string + expected syslog.DrainData + }{ + { + name: "drain-type=metrics", + url: "https://test.org/drain?drain-type=metrics", + expected: syslog.METRICS, + }, + { + name: "drain-type=logs", + url: "https://test.org/drain?drain-type=logs", + expected: syslog.LOGS_NO_EVENTS, + }, + { + name: "no drain-type parameter", + url: "https://test.org/drain", + expected: syslog.LOGS, + }, + { + name: "drain-type=all", + url: "https://test.org/drain?drain-type=all", + expected: syslog.LOGS_AND_METRICS, + }, + { + name: "include-metrics-deprecated=true", + url: "https://test.org/drain?include-metrics-deprecated=true", + expected: syslog.ALL, + }, + } + + for _, tc := range testCases { + By(tc.name) + bs := []syslog.Binding{ + {Drain: syslog.Drain{Url: tc.url}}, + } + f := newStubFetcher(bs, nil) + dp := bindings.NewDrainParamParser(f, true, logger) + + configedBindings, _ := dp.FetchBindings() + Expect(configedBindings[0].DrainData).To(Equal(tc.expected)) } - f := newStubFetcher(bs, nil) - wf := bindings.NewDrainParamParser(f, true) - - configedBindings, _ := wf.FetchBindings() - Expect(configedBindings[0].DrainData).To(Equal(syslog.METRICS)) - Expect(configedBindings[1].DrainData).To(Equal(syslog.LOGS_NO_EVENTS)) - Expect(configedBindings[2].DrainData).To(Equal(syslog.LOGS)) - Expect(configedBindings[3].DrainData).To(Equal(syslog.LOGS_AND_METRICS)) - Expect(configedBindings[4].DrainData).To(Equal(syslog.ALL)) }) It("omits bindings with bad Drain URLs", func() { @@ -114,9 +266,9 @@ var _ = Describe("Drain Param Config", func() { {Drain: syslog.Drain{Url: "https://test.org/drain?omit-metadata=true"}}, } f := newStubFetcher(bs, nil) - wf := bindings.NewDrainParamParser(f, true) + dp := bindings.NewDrainParamParser(f, true, logger) - configedBindings, err := wf.FetchBindings() + configedBindings, err := dp.FetchBindings() Expect(err).ToNot(HaveOccurred()) Expect(configedBindings).To(HaveLen(2)) Expect(configedBindings[0].Drain).To(Equal(syslog.Drain{Url: "https://test.org/drain?disable-metadata=true"})) @@ -125,9 +277,9 @@ var _ = Describe("Drain Param Config", func() { It("Returns a error when fetching fails", func() { f := newStubFetcher(nil, errors.New("Ahhh an error")) - wf := bindings.NewDrainParamParser(f, true) + dp := bindings.NewDrainParamParser(f, true, logger) - _, err := wf.FetchBindings() + _, err := dp.FetchBindings() Expect(err).To(MatchError("Ahhh an error")) }) }) @@ -151,3 +303,11 @@ func (f *stubFetcher) FetchBindings() ([]syslog.Binding, error) { func (f *stubFetcher) DrainLimit() int { return -1 } + +func NewLogTypeSet(logTypes ...syslog.LogType) *syslog.LogTypeSet { + set := make(syslog.LogTypeSet, len(logTypes)) + for _, t := range logTypes { + set[t] = struct{}{} + } + return &set +}