diff --git a/.chloggen/sinkingpoint_octet_counting.yaml b/.chloggen/sinkingpoint_octet_counting.yaml new file mode 100755 index 000000000000..e57ced544e04 --- /dev/null +++ b/.chloggen/sinkingpoint_octet_counting.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: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: syslogexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Adding support for sending rfc6587 octet counts in syslog messages + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [31013] + +# (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: [] diff --git a/exporter/syslogexporter/README.md b/exporter/syslogexporter/README.md index daca0259f1ba..a89c6e2b3cc3 100644 --- a/exporter/syslogexporter/README.md +++ b/exporter/syslogexporter/README.md @@ -27,6 +27,7 @@ This means that syslog messages received via the Syslog receiver and exported vi - `protocol` - (default = `rfc5424`) rfc5424/rfc3164 - `rfc5424` - Expects the syslog messages to be rfc5424 compliant - `rfc3164` - Expects the syslog messages to be rfc3164 compliant +- `enable_octet_counting` (default = `false`) - Whether or not to enable rfc6587 octet counting - `tls` - configuration for TLS/mTLS - `insecure` (default = `false`) whether to enable client transport security, by default, TLS is enabled. - `cert_file` - Path to the TLS cert to use for TLS required connections. Should only be used if `insecure` is set to `false`. diff --git a/exporter/syslogexporter/config.go b/exporter/syslogexporter/config.go index e51a944024bb..c5f0c9c3d767 100644 --- a/exporter/syslogexporter/config.go +++ b/exporter/syslogexporter/config.go @@ -18,6 +18,7 @@ var ( errInvalidEndpoint = errors.New("invalid endpoint: endpoint is required but it is not configured") errUnsupportedNetwork = errors.New("unsupported network: network is required, only tcp/udp supported") errUnsupportedProtocol = errors.New("unsupported protocol: Only rfc5424 and rfc3164 supported") + errOctetCounting = errors.New("octet counting is only supported for rfc5424 protocol") ) // Config defines configuration for Syslog exporter. @@ -33,6 +34,9 @@ type Config struct { // options: rfc5424, rfc3164 Protocol string `mapstructure:"protocol"` + // Wether or not to enable RFC 6587 Octet Counting. + EnableOctetCounting bool `mapstructure:"enable_octet_counting"` + // TLSSetting struct exposes TLS client configuration. TLSSetting configtls.TLSClientSetting `mapstructure:"tls"` @@ -63,6 +67,10 @@ func (cfg *Config) Validate() error { invalidFields = append(invalidFields, errUnsupportedProtocol) } + if cfg.EnableOctetCounting && cfg.Protocol != protocolRFC5424Str { + invalidFields = append(invalidFields, errOctetCounting) + } + if len(invalidFields) > 0 { return multierr.Combine(invalidFields...) } diff --git a/exporter/syslogexporter/exporter.go b/exporter/syslogexporter/exporter.go index 94b8508b2f60..3c69ced8210b 100644 --- a/exporter/syslogexporter/exporter.go +++ b/exporter/syslogexporter/exporter.go @@ -36,7 +36,7 @@ func initExporter(cfg *Config, createSettings exporter.CreateSettings) (*sysloge config: cfg, logger: createSettings.Logger, tlsConfig: tlsConfig, - formatter: createFormatter(cfg.Protocol), + formatter: createFormatter(cfg.Protocol, cfg.EnableOctetCounting), } s.logger.Info("Syslog Exporter configured", diff --git a/exporter/syslogexporter/formatter.go b/exporter/syslogexporter/formatter.go index c184ce2813e6..2b0a127aca46 100644 --- a/exporter/syslogexporter/formatter.go +++ b/exporter/syslogexporter/formatter.go @@ -7,9 +7,9 @@ import ( "go.opentelemetry.io/collector/pdata/plog" ) -func createFormatter(protocol string) formatter { +func createFormatter(protocol string, octetCounting bool) formatter { if protocol == protocolRFC5424Str { - return newRFC5424Formatter() + return newRFC5424Formatter(octetCounting) } return newRFC3164Formatter() } diff --git a/exporter/syslogexporter/rfc5424_formatter.go b/exporter/syslogexporter/rfc5424_formatter.go index 53e1bb872cc1..f13398f84703 100644 --- a/exporter/syslogexporter/rfc5424_formatter.go +++ b/exporter/syslogexporter/rfc5424_formatter.go @@ -13,10 +13,13 @@ import ( ) type rfc5424Formatter struct { + octetCounting bool } -func newRFC5424Formatter() *rfc5424Formatter { - return &rfc5424Formatter{} +func newRFC5424Formatter(octetCounting bool) *rfc5424Formatter { + return &rfc5424Formatter{ + octetCounting: octetCounting, + } } func (f *rfc5424Formatter) format(logRecord plog.LogRecord) string { @@ -30,6 +33,11 @@ func (f *rfc5424Formatter) format(logRecord plog.LogRecord) string { structuredData := f.formatStructuredData(logRecord) messageString := f.formatMessage(logRecord) formatted := fmt.Sprintf("<%s>%s %s %s %s %s %s %s%s\n", priorityString, versionString, timestampString, hostnameString, appnameString, pidString, messageIDString, structuredData, messageString) + + if f.octetCounting { + formatted = fmt.Sprintf("%d %s", len(formatted), formatted) + } + return formatted } diff --git a/exporter/syslogexporter/rfc5424_formatter_test.go b/exporter/syslogexporter/rfc5424_formatter_test.go index d88fb9f53a88..e74a052e2e13 100644 --- a/exporter/syslogexporter/rfc5424_formatter_test.go +++ b/exporter/syslogexporter/rfc5424_formatter_test.go @@ -29,8 +29,10 @@ func TestRFC5424Formatter(t *testing.T) { require.NoError(t, err) logRecord.SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) - actual := newRFC5424Formatter().format(logRecord) + actual := newRFC5424Formatter(false).format(logRecord) assert.Equal(t, expected, actual) + octetCounting := newRFC5424Formatter(true).format(logRecord) + assert.Equal(t, fmt.Sprintf("%d %s", len(expected), expected), octetCounting) expected = "<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog 111 ID47 - BOMAn application event log entry...\n" logRecord = plog.NewLogRecord() @@ -45,8 +47,10 @@ func TestRFC5424Formatter(t *testing.T) { require.NoError(t, err) logRecord.SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) - actual = newRFC5424Formatter().format(logRecord) + actual = newRFC5424Formatter(false).format(logRecord) assert.Equal(t, expected, actual) + octetCounting = newRFC5424Formatter(true).format(logRecord) + assert.Equal(t, fmt.Sprintf("%d %s", len(expected), expected), octetCounting) // Test structured data expectedRegex := "\\<165\\>1 2003-08-24T12:14:15.000003Z 192\\.0\\.2\\.1 myproc 8710 - " + @@ -72,7 +76,7 @@ func TestRFC5424Formatter(t *testing.T) { require.NoError(t, err) logRecord.SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) - actual = newRFC5424Formatter().format(logRecord) + actual = newRFC5424Formatter(false).format(logRecord) assert.NoError(t, err) matched, err := regexp.MatchString(expectedRegex, actual) assert.NoError(t, err) @@ -89,6 +93,6 @@ func TestRFC5424Formatter(t *testing.T) { require.NoError(t, err) logRecord.SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) - actual = newRFC5424Formatter().format(logRecord) + actual = newRFC5424Formatter(false).format(logRecord) assert.Equal(t, expected, actual) }