Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[exporter/syslog]: fix default behaviour (disable tls and use proper defaults) #27424

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .chloggen/drosiek-syslog-defaults.yaml
Original file line number Diff line number Diff line change
@@ -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: syslogexporter

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: use proper defaults according to RFCs

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [25114]

# (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]
1 change: 0 additions & 1 deletion exporter/syslogexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,4 @@ Please see [example configurations](./examples/).
[syslog_receiver]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/syslogreceiver
[filelog_receiver]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/filelogreceiver
[cryptoTLS]: https://github.com/golang/go/blob/518889b35cb07f3e71963f2ccfc0f96ee26a51ce/src/crypto/tls/common.go#L706-L709
[development]: https://github.com/open-telemetry/opentelemetry-collector#development
[persistent_queue]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md#persistent-queue
67 changes: 46 additions & 21 deletions exporter/syslogexporter/sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const structuredData = "structured_data"
const message = "message"

const emptyValue = "-"
const emptyMessage = ""

type sender struct {
network string
Expand Down Expand Up @@ -131,10 +132,8 @@ func (s *sender) addStructuredData(msg map[string]any) {
return
}

sd, ok := msg[structuredData].(map[string]map[string]string)
if !ok {
msg[structuredData] = emptyValue
} else {
switch sd := msg[structuredData].(type) {
case map[string]map[string]string:
sdElements := []string{}
for key, val := range sd {
sdElements = append(sdElements, key)
Expand All @@ -143,44 +142,70 @@ func (s *sender) addStructuredData(msg map[string]any) {
}
}
msg[structuredData] = sdElements
case map[string]interface{}:
sdElements := []string{}
for key, val := range sd {
sdElements = append(sdElements, key)
vval, ok := val.(map[string]interface{})
if !ok {
continue
}
for k, v := range vval {
vv, ok := v.(string)
if !ok {
continue
}
sdElements = append(sdElements, fmt.Sprintf("%s=\"%s\"", k, vv))
}
}
msg[structuredData] = sdElements
default:
msg[structuredData] = emptyValue
}
}

func populateDefaults(msg map[string]any, msgProperties []string) {

for _, msgProperty := range msgProperties {
msgValue, ok := msg[msgProperty]
if !ok && msgProperty == priority {
msg[msgProperty] = defaultPriority
return
if _, ok := msg[msgProperty]; ok {
continue
}
if !ok && msgProperty == version {

switch msgProperty {
case priority:
msg[msgProperty] = defaultPriority
case version:
msg[msgProperty] = versionRFC5424
return
}
if !ok && msgProperty == facility {
case facility:
msg[msgProperty] = defaultFacility
return
}
if !ok {
case message:
msg[msgProperty] = emptyMessage
default:
msg[msgProperty] = emptyValue
return
}
msg[msgProperty] = msgValue
}
}

func (s *sender) formatRFC3164(msg map[string]any, timestamp time.Time) string {
msgProperties := []string{priority, hostname, message}
populateDefaults(msg, msgProperties)
timestampString := timestamp.Format("2006-01-02T15:04:05.000-03:00")
return fmt.Sprintf("<%d>%s %s %s", msg[priority], timestampString, msg[hostname], msg[message])
timestampString := timestamp.Format("Jan 02 15:04:05")
return fmt.Sprintf("<%d>%s %s%s", msg[priority], timestampString, msg[hostname], formatMessagePart(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)
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], msg[message])

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]))
}

func formatMessagePart(message any) string {
msg := message.(string)
if msg != emptyMessage {
msg = " " + msg
}

return msg
}
58 changes: 55 additions & 3 deletions exporter/syslogexporter/sender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestFormatRFC5424(t *testing.T) {

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")
assert.Equal(t, expected, s.formatRFC5424(msg, timeObj1))
assert.Equal(t, expected, s.formatMsg(msg, timeObj1))
assert.Nil(t, err)

msg2 := map[string]any{
Expand All @@ -50,7 +50,7 @@ func TestFormatRFC5424(t *testing.T) {
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")
assert.Nil(t, err)
assert.Equal(t, expected2, s.formatRFC5424(msg2, timeObj2))
assert.Equal(t, expected2, s.formatMsg(msg2, timeObj2))

msg3 := map[string]any{
"timestamp": "2003-08-24T05:14:15.000003-07:00",
Expand All @@ -76,12 +76,64 @@ func TestFormatRFC5424(t *testing.T) {
"\\[\\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")
assert.Nil(t, err)
formattedMsg := s.formatRFC5424(msg3, timeObj3)
formattedMsg := s.formatMsg(msg3, timeObj3)
matched, err := regexp.MatchString(expectedForm, formattedMsg)
assert.Nil(t, err)
assert.Equal(t, true, matched, fmt.Sprintf("unexpected form of formatted message, formatted message: %s, regexp: %s", formattedMsg, expectedForm))
assert.Equal(t, true, strings.Contains(formattedMsg, "Realm=\"SecureAuth0\""))
assert.Equal(t, true, strings.Contains(formattedMsg, "UserHostAddress=\"192.168.2.132\""))
assert.Equal(t, true, strings.Contains(formattedMsg, "UserID=\"Tester2\""))
assert.Equal(t, true, strings.Contains(formattedMsg, "PEN=\"27389\""))

// 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")
assert.Equal(t, expected, s.formatMsg(msg4, timeObj1))
assert.Nil(t, err)

msg5 := map[string]any{
"timestamp": "2003-08-24T05:14:15.000003-07:00",
"appname": "myproc",
"facility": 20,
"hostname": "192.0.2.1",
"log.file.name": "syslog",
"message": "It's time to make the do-nuts.",
"priority": 165,
"proc_id": "8710",
"version": 1,
"structured_data": map[string]interface{}{
"SecureAuth@27389": map[string]interface{}{
"PEN": "27389",
"Realm": "SecureAuth0",
"UserHostAddress": "192.168.2.132",
"UserID": "Tester2",
},
},
}

expectedForm = "\\<165\\>1 2003-08-24T05:14:15-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")
assert.Nil(t, err)
formattedMsg = s.formatMsg(msg5, timeObj5)
matched, err = regexp.MatchString(expectedForm, formattedMsg)
assert.Nil(t, err)
assert.Equal(t, true, matched, fmt.Sprintf("unexpected form of formatted message, formatted message: %s, regexp: %s", formattedMsg, expectedForm))
assert.Equal(t, true, strings.Contains(formattedMsg, "Realm=\"SecureAuth0\""))
assert.Equal(t, true, strings.Contains(formattedMsg, "UserHostAddress=\"192.168.2.132\""))
assert.Equal(t, true, strings.Contains(formattedMsg, "UserID=\"Tester2\""))
assert.Equal(t, true, strings.Contains(formattedMsg, "PEN=\"27389\""))
}

func TestFormatRFC3164(t *testing.T) {

s := sender{protocol: protocolRFC3164Str}

// 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")
assert.Equal(t, expected, s.formatMsg(msg4, timeObj1))
assert.Nil(t, err)
}
2 changes: 1 addition & 1 deletion pkg/stanza/operator/input/syslog/syslog.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (c Config) Build(logger *zap.SugaredLogger) (operator.Operator, error) {

udpInput, err := udpInputCfg.Build(logger)
if err != nil {
return nil, fmt.Errorf("failed to resolve upd config: %w", err)
return nil, fmt.Errorf("failed to resolve udp config: %w", err)
}

udpInput.SetOutputIDs([]string{syslogParser.ID()})
Expand Down