Skip to content

Commit

Permalink
[exporter/syslog]: fix default behaviour (disable tls and use proper …
Browse files Browse the repository at this point in the history
…defaults) (open-telemetry#27424)

**Description:**

- fix defaults
- fix some typos
- correctly handle data structures which are output of syslog receiver
- allow to not use tls and disable it by default

**Link to tracking Issue:** open-telemetry#25114 

**Testing:** 
Unit tests

**Documentation:** 
N/A

---------

Signed-off-by: Dominik Rosiek <drosiek@sumologic.com>
  • Loading branch information
sumo-drosiek authored and jmsnll committed Nov 12, 2023
1 parent c254b68 commit 2183a13
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 26 deletions.
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

0 comments on commit 2183a13

Please sign in to comment.