From 4e3323bd9c362ad35a33100168207b7908281b6c Mon Sep 17 00:00:00 2001 From: Dominik Rosiek <58699848+sumo-drosiek@users.noreply.github.com> Date: Mon, 16 Oct 2023 18:26:49 +0200 Subject: [PATCH] feat: add integration test for syslog exporter (and receiver) (#27464) **Description:** Adding integration tests for syslog exporter (and syslog receiver) and fixing bugs which has been found during the process **Link to tracking Issue:** #21245 **Testing:** Integration tests and more unit tests **Documentation:** N/A --------- Signed-off-by: Dominik Rosiek Co-authored-by: Daniel Jaglowski --- .chloggen/drosiek-integration-tests.yaml | 27 ++++ exporter/syslogexporter/sender.go | 13 +- exporter/syslogexporter/sender_test.go | 41 +++-- testbed/datareceivers/carbon.go | 2 +- testbed/datareceivers/syslog.go | 72 +++++++++ testbed/go.mod | 14 ++ testbed/go.sum | 6 + testbed/testbed/components.go | 4 + testbed/tests/syslog_integration_test.go | 197 +++++++++++++++++++++++ 9 files changed, 359 insertions(+), 17 deletions(-) create mode 100755 .chloggen/drosiek-integration-tests.yaml create mode 100644 testbed/datareceivers/syslog.go create mode 100644 testbed/tests/syslog_integration_test.go diff --git a/.chloggen/drosiek-integration-tests.yaml b/.chloggen/drosiek-integration-tests.yaml new file mode 100755 index 000000000000..310b507af65c --- /dev/null +++ b/.chloggen/drosiek-integration-tests.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: syslog + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: add integration tests and fix related bugs + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [21245] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/exporter/syslogexporter/sender.go b/exporter/syslogexporter/sender.go index c4caeaadf1db..9396cbcc059c 100644 --- a/exporter/syslogexporter/sender.go +++ b/exporter/syslogexporter/sender.go @@ -186,17 +186,24 @@ func populateDefaults(msg map[string]any, msgProperties []string) { } func (s *sender) formatRFC3164(msg map[string]any, timestamp time.Time) string { - msgProperties := []string{priority, hostname, message} + msgProperties := []string{priority, hostname, message, app} populateDefaults(msg, msgProperties) timestampString := timestamp.Format("Jan 02 15:04:05") - return fmt.Sprintf("<%d>%s %s%s", msg[priority], timestampString, msg[hostname], formatMessagePart(msg[message])) + appname := "" + if msg[app] != emptyValue { + appname = msg[app].(string) + ":" + } + if appname != "" && message != emptyMessage { + appname += " " + } + return fmt.Sprintf("<%d>%s %s %s%s", msg[priority], timestampString, msg[hostname], appname, msg[message]) } func (s *sender) formatRFC5424(msg map[string]any, timestamp time.Time) string { msgProperties := []string{priority, version, hostname, app, pid, msgID, message, structuredData} populateDefaults(msg, msgProperties) s.addStructuredData(msg) - timestampString := timestamp.Format(time.RFC3339) + timestampString := timestamp.Format(time.RFC3339Nano) return fmt.Sprintf("<%d>%d %s %s %s %s %s %s%s", msg[priority], msg[version], timestampString, msg[hostname], msg[app], msg[pid], msg[msgID], msg[structuredData], formatMessagePart(msg[message])) } diff --git a/exporter/syslogexporter/sender_test.go b/exporter/syslogexporter/sender_test.go index 1620a028a912..68b178220cdd 100644 --- a/exporter/syslogexporter/sender_test.go +++ b/exporter/syslogexporter/sender_test.go @@ -29,8 +29,8 @@ func TestFormatRFC5424(t *testing.T) { "version": 1, } - expected := "<165>1 2003-08-24T05:14:15-07:00 192.0.2.1 myproc 8710 - - It's time to make the do-nuts." - timeObj1, err := time.Parse(time.RFC3339, "2003-08-24T05:14:15.000003-07:00") + expected := "<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - It's time to make the do-nuts." + timeObj1, err := time.Parse(time.RFC3339Nano, "2003-08-24T05:14:15.000003-07:00") assert.Equal(t, expected, s.formatMsg(msg, timeObj1)) assert.Nil(t, err) @@ -47,8 +47,8 @@ func TestFormatRFC5424(t *testing.T) { "version": 1, } - expected2 := "<165>1 2003-10-11T22:14:15Z mymachine.example.com evntslog 111 ID47 - BOMAn application event log entry..." - timeObj2, err := time.Parse(time.RFC3339, "2003-10-11T22:14:15.003Z") + expected2 := "<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog 111 ID47 - BOMAn application event log entry..." + timeObj2, err := time.Parse(time.RFC3339Nano, "2003-10-11T22:14:15.003Z") assert.Nil(t, err) assert.Equal(t, expected2, s.formatMsg(msg2, timeObj2)) @@ -72,9 +72,9 @@ func TestFormatRFC5424(t *testing.T) { }, } - expectedForm := "\\<165\\>1 2003-08-24T05:14:15-07:00 192\\.0\\.2\\.1 myproc 8710 - " + + expectedForm := "\\<165\\>1 2003-08-24T05:14:15.000003-07:00 192\\.0\\.2\\.1 myproc 8710 - " + "\\[\\S+ \\S+ \\S+ \\S+ \\S+\\] It's time to make the do-nuts\\." - timeObj3, err := time.Parse(time.RFC3339, "2003-08-24T05:14:15.000003-07:00") + timeObj3, err := time.Parse(time.RFC3339Nano, "2003-08-24T05:14:15.000003-07:00") assert.Nil(t, err) formattedMsg := s.formatMsg(msg3, timeObj3) matched, err := regexp.MatchString(expectedForm, formattedMsg) @@ -87,8 +87,8 @@ func TestFormatRFC5424(t *testing.T) { // Test defaults msg4 := map[string]any{} - expected = "<165>1 2003-08-24T05:14:15-07:00 - - - - -" - timeObj1, err = time.Parse(time.RFC3339, "2003-08-24T05:14:15.000003-07:00") + expected = "<165>1 2003-08-24T05:14:15.000003-07:00 - - - - -" + timeObj1, err = time.Parse(time.RFC3339Nano, "2003-08-24T05:14:15.000003-07:00") assert.Equal(t, expected, s.formatMsg(msg4, timeObj1)) assert.Nil(t, err) @@ -112,9 +112,9 @@ func TestFormatRFC5424(t *testing.T) { }, } - expectedForm = "\\<165\\>1 2003-08-24T05:14:15-07:00 192\\.0\\.2\\.1 myproc 8710 - " + + expectedForm = "\\<165\\>1 2003-08-24T05:14:15.000003-07:00 192\\.0\\.2\\.1 myproc 8710 - " + "\\[\\S+ \\S+ \\S+ \\S+ \\S+\\] It's time to make the do-nuts\\." - timeObj5, err := time.Parse(time.RFC3339, "2003-08-24T05:14:15.000003-07:00") + timeObj5, err := time.Parse(time.RFC3339Nano, "2003-08-24T05:14:15.000003-07:00") assert.Nil(t, err) formattedMsg = s.formatMsg(msg5, timeObj5) matched, err = regexp.MatchString(expectedForm, formattedMsg) @@ -130,10 +130,25 @@ func TestFormatRFC3164(t *testing.T) { s := sender{protocol: protocolRFC3164Str} + msg := map[string]interface{}{ + "message": "'su root' failed for lonvick on /dev/pts/8", + "hostname": "mymachine", + "appname": "su", + "priority": int64(34), + "facility": int64(4), + } + + expected := "<34>Aug 24 05:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8" + timeObj1, err := time.Parse(time.RFC3339Nano, "2003-08-24T05:14:15.000003-07:00") + assert.Equal(t, expected, s.formatMsg(msg, timeObj1)) + assert.Nil(t, err) + // Test defaults - msg4 := map[string]any{} - expected := "<165>Aug 24 05:14:15 -" - timeObj1, err := time.Parse(time.RFC3339, "2003-08-24T05:14:15.000003-07:00") + msg4 := map[string]interface{}{ + "message": "-", + } + expected = "<165>Aug 24 05:14:15 - -" + timeObj1, err = time.Parse(time.RFC3339Nano, "2003-08-24T05:14:15.000003-07:00") assert.Equal(t, expected, s.formatMsg(msg4, timeObj1)) assert.Nil(t, err) } diff --git a/testbed/datareceivers/carbon.go b/testbed/datareceivers/carbon.go index 2ef7e3f2570f..f0667e011d31 100644 --- a/testbed/datareceivers/carbon.go +++ b/testbed/datareceivers/carbon.go @@ -24,7 +24,7 @@ type CarbonDataReceiver struct { receiver receiver.Metrics } -// Ensure CarbonDataReceiver implements MetricDataSender. +// Ensure CarbonDataReceiver implements DataReceiver var _ testbed.DataReceiver = (*CarbonDataReceiver)(nil) // NewCarbonDataReceiver creates a new CarbonDataReceiver that will listen on the diff --git a/testbed/datareceivers/syslog.go b/testbed/datareceivers/syslog.go new file mode 100644 index 000000000000..b064a22898e0 --- /dev/null +++ b/testbed/datareceivers/syslog.go @@ -0,0 +1,72 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package datareceivers // import "github.com/open-telemetry/opentelemetry-collector-contrib/testbed/datareceivers" + +import ( + "context" + "fmt" + + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receivertest" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/input/tcp" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/syslogreceiver" + "github.com/open-telemetry/opentelemetry-collector-contrib/testbed/testbed" +) + +// SyslogDataReceiver implements Syslog format receiver. +type SyslogDataReceiver struct { + testbed.DataReceiverBase + receiver receiver.Logs + protocol string +} + +// Ensure SyslogDataReceiver implements LogDataReceiver. +var _ testbed.DataReceiver = (*SyslogDataReceiver)(nil) + +// NewSyslogDataReceiver creates a new SyslogDataReceiver that will listen on the +// specified port after Start is called. +func NewSyslogDataReceiver(protocol string, port int) *SyslogDataReceiver { + return &SyslogDataReceiver{DataReceiverBase: testbed.DataReceiverBase{Port: port}, protocol: protocol} +} + +// Start the receiver. +func (cr *SyslogDataReceiver) Start(_ consumer.Traces, _ consumer.Metrics, lc consumer.Logs) error { + factory := syslogreceiver.NewFactory() + addr := fmt.Sprintf("127.0.0.1:%d", cr.Port) + cfg := factory.CreateDefaultConfig().(*syslogreceiver.SysLogConfig) + cfg.InputConfig.TCP = &tcp.BaseConfig{ + ListenAddress: addr, + } + cfg.InputConfig.Protocol = cr.protocol + + set := receivertest.NewNopCreateSettings() + var err error + cr.receiver, err = factory.CreateLogsReceiver(context.Background(), set, cfg, lc) + if err != nil { + return err + } + + return cr.receiver.Start(context.Background(), componenttest.NewNopHost()) +} + +// Stop the receiver. +func (cr *SyslogDataReceiver) Stop() error { + return cr.receiver.Shutdown(context.Background()) +} + +// GenConfigYAMLStr returns receiver config for the agent. +func (cr *SyslogDataReceiver) GenConfigYAMLStr() string { + // Note that this generates an receiver config for agent. + return fmt.Sprintf(` + syslog: + endpoint: "127.0.0.1:%d"`, cr.Port) +} + +// ProtocolName returns protocol name as it is specified in Collector config. +func (cr *SyslogDataReceiver) ProtocolName() string { + return "tcp" +} diff --git a/testbed/go.mod b/testbed/go.mod index 7a2cac8a9510..ca47715e20af 100644 --- a/testbed/go.mod +++ b/testbed/go.mod @@ -10,10 +10,12 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sapmexporter v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter v0.87.0 + github.com/open-telemetry/opentelemetry-collector-contrib/exporter/syslogexporter v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/internal/splunk v0.87.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/carbonreceiver v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/datadogreceiver v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.87.0 @@ -22,6 +24,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sapmreceiver v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/signalfxreceiver v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/splunkhecreceiver v0.87.0 + github.com/open-telemetry/opentelemetry-collector-contrib/receiver/syslogreceiver v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/testbed/mockdatareceivers/mockawsxrayreceiver v0.87.0 github.com/open-telemetry/opentelemetry-collector-contrib/testbed/mockdatasenders/mockdatadogagentexporter v0.87.0 @@ -79,6 +82,7 @@ require ( github.com/DataDog/datadog-agent/pkg/trace/exportable v0.0.0-20201016145401-4646cf596b02 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect + github.com/antonmedv/expr v1.15.3 // indirect github.com/apache/thrift v0.19.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aws/aws-sdk-go v1.45.24 // indirect @@ -146,6 +150,7 @@ require ( github.com/hetznercloud/hcloud-go/v2 v2.0.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/influxdata/go-syslog/v3 v3.0.1-0.20210608084020-ac565dc76ba6 // indirect github.com/ionos-cloud/sdk-go/v6 v6.1.8 // indirect github.com/jaegertracing/jaeger v1.48.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -157,6 +162,7 @@ require ( github.com/knadh/koanf/v2 v2.0.1 // indirect github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect github.com/kylelemons/godebug v1.1.0 // indirect + github.com/leodido/ragel-machinery v0.0.0-20181214104525-299bdde78165 // indirect github.com/linode/linodego v1.19.0 // indirect github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -291,6 +297,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signa replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/splunkhecexporter => ../exporter/splunkhecexporter +replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/syslogexporter => ../exporter/syslogexporter + replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter => ../exporter/zipkinexporter replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/common => ../internal/common @@ -329,6 +337,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/signa replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/splunkhecreceiver => ../receiver/splunkhecreceiver +replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/syslogreceiver => ../receiver/syslogreceiver + replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver => ../receiver/zipkinreceiver replace github.com/open-telemetry/opentelemetry-collector-contrib/testbed/mockdatareceivers/mockawsxrayreceiver => ../testbed/mockdatareceivers/mockawsxrayreceiver @@ -341,6 +351,10 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/corei replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry => ../pkg/resourcetotelemetry +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza => ../pkg/stanza + +replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage => ../extension/storage + retract ( v0.76.2 v0.76.1 diff --git a/testbed/go.sum b/testbed/go.sum index d2670bd85f23..d51d4897828b 100644 --- a/testbed/go.sum +++ b/testbed/go.sum @@ -94,6 +94,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antonmedv/expr v1.15.3 h1:q3hOJZNvLvhqE8OHBs1cFRdbXFNKuA+bHmRaI+AmRmI= +github.com/antonmedv/expr v1.15.3/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE= github.com/apache/thrift v0.19.0 h1:sOqkWPzMj7w6XaYbJQG7m4sGqVolaW/0D28Ln7yPzMk= github.com/apache/thrift v0.19.0/go.mod h1:SUALL216IiaOw2Oy+5Vs9lboJ/t9g40C+G07Dc0QC1I= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -417,6 +419,8 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/go-syslog/v3 v3.0.1-0.20210608084020-ac565dc76ba6 h1:s9ZL6ZhFF8y6ebnm1FLvobkzoIu5xwDQUcRPk/IEhpM= +github.com/influxdata/go-syslog/v3 v3.0.1-0.20210608084020-ac565dc76ba6/go.mod h1:aXdIdfn2OcGnMhOTojXmwZqXKgC3MU5riiNvzwwG9OY= github.com/ionos-cloud/sdk-go/v6 v6.1.8 h1:493wE/BkZxJf7x79UCE0cYGPZoqQcPiEBALvt7uVGY0= github.com/ionos-cloud/sdk-go/v6 v6.1.8/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/jaegertracing/jaeger v1.48.0 h1:YuKooQ7qJsjgxws9xuf8C/BLNTPx8qTAJz4wv7IHhSc= @@ -465,6 +469,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/ragel-machinery v0.0.0-20181214104525-299bdde78165 h1:bCiVCRCs1Heq84lurVinUPy19keqGEe4jh5vtK37jcg= +github.com/leodido/ragel-machinery v0.0.0-20181214104525-299bdde78165/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg= github.com/linode/linodego v1.19.0 h1:n4WJrcr9+30e9JGZ6DI0nZbm5SdAj1kSwvvt/998YUw= github.com/linode/linodego v1.19.0/go.mod h1:XZFR+yJ9mm2kwf6itZ6SCpu+6w3KnIevV0Uu5HNWJgQ= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= diff --git a/testbed/testbed/components.go b/testbed/testbed/components.go index 4a8aec1399a9..bc93a52c9329 100644 --- a/testbed/testbed/components.go +++ b/testbed/testbed/components.go @@ -20,9 +20,11 @@ import ( "go.uber.org/multierr" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/syslogexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusreceiver" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/syslogreceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver" ) @@ -43,6 +45,7 @@ func Components() ( jaegerreceiver.NewFactory(), opencensusreceiver.NewFactory(), otlpreceiver.NewFactory(), + syslogreceiver.NewFactory(), zipkinreceiver.NewFactory(), ) errs = multierr.Append(errs, err) @@ -52,6 +55,7 @@ func Components() ( opencensusexporter.NewFactory(), otlpexporter.NewFactory(), otlphttpexporter.NewFactory(), + syslogexporter.NewFactory(), zipkinexporter.NewFactory(), ) errs = multierr.Append(errs, err) diff --git a/testbed/tests/syslog_integration_test.go b/testbed/tests/syslog_integration_test.go new file mode 100644 index 000000000000..512fb115f631 --- /dev/null +++ b/testbed/tests/syslog_integration_test.go @@ -0,0 +1,197 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package tests // import "github.com/open-telemetry/opentelemetry-collector-contrib/testbed/tests" + +import ( + "fmt" + "net" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/otelcol" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + + "github.com/open-telemetry/opentelemetry-collector-contrib/testbed/datareceivers" + "github.com/open-telemetry/opentelemetry-collector-contrib/testbed/testbed" +) + +type expectedDataType struct { + message string + severityNumber plog.SeverityNumber + severityText string + timestamp pcommon.Timestamp + attributes map[string]interface{} +} + +func TestSyslogComplementaryRFC5424(t *testing.T) { + expectedData := []expectedDataType{ + { + message: "<165>1 2003-10-11T22:14:15.003Z mymachine.example.com eventslog - ID47 [exampleSDID@32473 iut=\"3\"] Some message", + severityNumber: 10, + severityText: "notice", + timestamp: 1065910455003000000, + attributes: map[string]interface{}{ + "message": "Some message", + "msg_id": "ID47", + "structured_data": map[string]interface{}{ + "exampleSDID@32473": map[string]interface{}{ + "iut": "3", + }, + }, + "hostname": "mymachine.example.com", + "appname": "eventslog", + "priority": int64(165), + "version": int64(1), + "facility": int64(20), + }, + }, + { + message: "<17>3 2003-10-11T22:14:15.008Z - - - - -", + severityNumber: 19, + severityText: "alert", + timestamp: 1065910455008000000, + attributes: map[string]interface{}{ + "priority": int64(17), + "version": int64(3), + "facility": int64(2), + }, + }, + } + + complementaryTest(t, "rfc5424", expectedData) +} + +func TestSyslogComplementaryRFC3164(t *testing.T) { + expectedData := []expectedDataType{ + { + message: "<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8", + timestamp: 1697062455000000000, + severityNumber: 18, + severityText: "crit", + attributes: map[string]interface{}{ + "message": "'su root' failed for lonvick on /dev/pts/8", + "hostname": "mymachine", + "appname": "su", + "priority": int64(34), + "facility": int64(4), + }, + }, + { + message: "<19>Oct 11 22:14:15 - -", + timestamp: 1697062455000000000, + severityNumber: 17, + severityText: "err", + attributes: map[string]interface{}{ + "message": "-", + "priority": int64(19), + "facility": int64(2), + }, + }, + } + + complementaryTest(t, "rfc3164", expectedData) +} + +func componentFactories(t *testing.T) otelcol.Factories { + factories, err := testbed.Components() + require.NoError(t, err) + return factories +} + +func complementaryTest(t *testing.T, rfc string, expectedData []expectedDataType) { + // Prepare ports + port := testbed.GetAvailablePort(t) + inputPort := testbed.GetAvailablePort(t) + + // Start SyslogDataReceiver + syslogReceiver := datareceivers.NewSyslogDataReceiver(rfc, port) + backend := testbed.NewMockBackend("mockbackend.log", syslogReceiver) + require.NoError(t, backend.Start()) + backend.EnableRecording() + + // Prepare and run collector + config := ` +receivers: + syslog/client: + protocol: %s + tcp: + listen_address: '127.0.0.1:%d' +exporters: + syslog/client: + endpoint: 127.0.0.1 + network: tcp + protocol: %s + port: %d + tls: + insecure: true +service: + pipelines: + logs/client: + receivers: + - syslog/client + exporters: + - syslog/client` + + collector := testbed.NewInProcessCollector(componentFactories(t)) + _, err := collector.PrepareConfig(fmt.Sprintf(config, rfc, inputPort, rfc, port)) + + require.NoError(t, err) + err = collector.Start(testbed.StartParams{ + Name: "Agent", + }) + require.NoError(t, err) + + // prepare data + + message := "" + expectedAttributes := []map[string]interface{}{} + expectedLogs := plog.NewLogs() + rl := expectedLogs.ResourceLogs().AppendEmpty() + lrs := rl.ScopeLogs().AppendEmpty().LogRecords() + + for _, e := range expectedData { + lr := lrs.AppendEmpty() + lr.Body().SetStr(e.message) + lr.SetSeverityNumber(e.severityNumber) + lr.SetSeverityText(e.severityText) + lr.SetTimestamp(e.timestamp) + expectedAttributes = append(expectedAttributes, e.attributes) + message += e.message + "\n" + } + + // Prepare client + conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", inputPort)) + require.NoError(t, err) + + // Write requests + fmt.Fprint(conn, message) + + // Wait for all messages + for len(backend.ReceivedLogs) < 1 { + time.Sleep(100 * time.Millisecond) + } + + require.Equal(t, len(backend.ReceivedLogs), 1) + require.Equal(t, backend.ReceivedLogs[0].ResourceLogs().Len(), 1) + require.Equal(t, backend.ReceivedLogs[0].ResourceLogs().At(0).ScopeLogs().Len(), 1) + require.Equal(t, backend.ReceivedLogs[0].ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().Len(), len(expectedData)) + + // Clean received logs + attributes := []map[string]interface{}{} + + lrs = backend.ReceivedLogs[0].ResourceLogs().At(0).ScopeLogs().At(0).LogRecords() + for i := 0; i < lrs.Len(); i++ { + lrs.At(i).SetObservedTimestamp(0) + + attributes = append(attributes, lrs.At(i).Attributes().AsRaw()) + lrs.At(i).Attributes().Clear() + } + + // Assert + assert.Equal(t, expectedLogs, backend.ReceivedLogs[0]) + assert.Equal(t, expectedAttributes, attributes) +}