From bfad53cbe32335c7602c3bc1e0d4752652545e08 Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 27 Feb 2026 16:57:27 +0100 Subject: [PATCH 1/9] Expose functionality to drop empty MSG field for RFC5424 syslogs --- .../components/loki/loki.source.syslog.md | 1 + .../loki/source/syslog/config/config.go | 3 + .../internal/syslogtarget/syslogtarget.go | 12 ++- .../syslogtarget/syslogtarget_test.go | 96 +++++++++++++++++++ .../component/loki/source/syslog/types.go | 8 ++ .../loki/source/syslog/types_test.go | 1 + 6 files changed, 119 insertions(+), 2 deletions(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index ca3e483777c..7753891b096 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -115,6 +115,7 @@ Only the `address` field is required and any omitted fields take their default v | Name | Type | Description | Default | Required | |-----------------------------------|---------------|----------------------------------------------------------------------------------------|-------------|----------| | `address` | `string` | The `` address to listen to for syslog messages. | | yes | +| `allow_empty_rfc5424_msg` | `bool` | Whether to forward RFC5424 messages with empty MSG content. When `false`, such messages are dropped. Only applies when `syslog_format` is `rfc5424`. | `false` | no | | `idle_timeout` | `duration` | The idle timeout for TCP connections. | `"120s"` | no | | `label_structured_data` | `bool` | Whether to translate syslog structured data to Loki labels. | `false` | no | | `labels` | `map(string)` | The labels to associate with each received syslog record. | `{}` | no | diff --git a/internal/component/loki/source/syslog/config/config.go b/internal/component/loki/source/syslog/config/config.go index d0203c81dc3..f6ced4c771f 100644 --- a/internal/component/loki/source/syslog/config/config.go +++ b/internal/component/loki/source/syslog/config/config.go @@ -126,6 +126,9 @@ type SyslogTargetConfig struct { // When false, the year will default to 0. RFC3164DefaultToCurrentYear bool `yaml:"rfc3164_default_to_current_year"` + // AllowEmptyRFC5424Msg when true, forwards RFC5424 messages with empty MSG content. Default false. + AllowEmptyRFC5424Msg bool `yaml:"allow_empty_rfc5424_msg"` + // RFC3164CiscoComponents enables and configures Cisco IOS syslog parsing. RFC3164CiscoComponents *RFC3164CiscoComponents `yaml:"rfc3164_cisco_components"` } diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go index b1bea63c47b..4f9ed482507 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go @@ -138,7 +138,10 @@ func (t *SyslogTarget) handleMessageError(err error) { func (t *SyslogTarget) handleMessageRFC5424(connLabels labels.Labels, msg *rfc5424.SyslogMessage) { if msg.Message == nil { t.metrics.syslogEmptyMessages.Inc() - return + + if !t.config.AllowEmptyRFC5424Msg { + return + } } lb := labels.NewBuilder(connLabels) @@ -197,7 +200,10 @@ func (t *SyslogTarget) handleMessageRFC5424(connLabels labels.Labels, msg *rfc54 timestamp = time.Now() } - m := *msg.Message + m := "" + if msg.Message != nil { + m = *msg.Message + } if t.config.UseRFC5424Message { fullMsg, err := msg.String() if err != nil { @@ -220,6 +226,7 @@ func (t *SyslogTarget) handleMessageRFC5424(connLabels labels.Labels, msg *rfc54 func (t *SyslogTarget) handleMessageRFC3164(connLabels labels.Labels, msg *rfc3164.SyslogMessage) { if msg.Message == nil { + // Drop RFC3164 messages with an empty Message t.metrics.syslogEmptyMessages.Inc() return } @@ -283,6 +290,7 @@ func (t *SyslogTarget) handleMessageRFC3164(connLabels labels.Labels, msg *rfc31 } func (t *SyslogTarget) handleMessageRaw(connLabels labels.Labels, msg *syslog.Base) { + // Drop raw logs with nil or empty message - this would mean the line itself is empty (e.g. "\n") if msg.Message == nil || *msg.Message == "" { t.metrics.syslogEmptyMessages.Inc() return diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go index 781944f06f8..15ac942dfa1 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go @@ -567,6 +567,102 @@ func TestSyslogTarget_RFC5424Messages(t *testing.T) { } } +func TestSyslogTarget_RFC5424MessageEmptyMSGWhenAllowed(t *testing.T) { + msg := `<14>1 2026-02-19T14:57:17.097Z secfw-a RT_FLOW - RT_FLOW_SESSION_DENY [junos@2636.1.1.1.2.129 application="UNKNOWN"]` + + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + handler := loki.NewCollectingHandler() + defer handler.Stop() + + metrics := NewMetrics(nil) + tgt, err := NewSyslogTarget(TargetParams{ + Metrics: metrics, + Logger: logger, + Handler: handler, + Relabel: []*relabel.Config{}, + Config: &scrapeconfig.SyslogTargetConfig{ + ListenAddress: "127.0.0.1:0", + ListenProtocol: ProtocolTCP, + LabelStructuredData: true, + UseRFC5424Message: true, + UseIncomingTimestamp: true, + AllowEmptyRFC5424Msg: true, + Labels: model.LabelSet{ + "test": "syslog_target", + }, + }, + }) + require.NoError(t, err) + require.Eventually(t, tgt.Ready, time.Second, 10*time.Millisecond) + defer func() { + require.NoError(t, tgt.Stop()) + }() + + addr := tgt.ListenAddress().String() + c, err := net.Dial(ProtocolTCP, addr) + require.NoError(t, err) + + err = writeMessagesToStream(c, []string{msg}, fmtNewline) + require.NoError(t, err) + require.NoError(t, c.Close()) + + require.Eventuallyf(t, func() bool { + return len(handler.Received()) == 1 + }, time.Second, time.Millisecond, "Expected to receive 1 message, got %d.", len(handler.Received())) + + entry := handler.Received()[0] + require.Equal(t, msg, entry.Line, "Line should be the full RFC 5424 string when MSG part is empty") + require.NotZero(t, entry.Timestamp) + require.Equal(t, time.Date(2026, 2, 19, 14, 57, 17, 97*int(time.Millisecond), time.UTC), entry.Timestamp) + require.Equal(t, model.LabelSet{"test": "syslog_target"}, entry.Labels) +} + +func TestSyslogTarget_RFC5424MessageEmptyMSGWhenNotAllowed(t *testing.T) { + // RFC5424 message with empty MSG part (no content after structured data) + msg := `<14>1 2026-02-19T14:57:17.097Z secfw-a RT_FLOW - RT_FLOW_SESSION_DENY [junos@2636.1.1.1.2.129 application="UNKNOWN"]` + + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + handler := loki.NewCollectingHandler() + defer handler.Stop() + + metrics := NewMetrics(nil) + tgt, err := NewSyslogTarget(TargetParams{ + Metrics: metrics, + Logger: logger, + Handler: handler, + Relabel: []*relabel.Config{}, + Config: &scrapeconfig.SyslogTargetConfig{ + ListenAddress: "127.0.0.1:0", + ListenProtocol: ProtocolTCP, + AllowEmptyRFC5424Msg: false, + LabelStructuredData: true, + Labels: model.LabelSet{ + "test": "syslog_target", + }, + }, + }) + require.NoError(t, err) + require.Eventually(t, tgt.Ready, time.Second, 10*time.Millisecond) + defer func() { + require.NoError(t, tgt.Stop()) + }() + + addr := tgt.ListenAddress().String() + c, err := net.Dial(ProtocolTCP, addr) + require.NoError(t, err) + + err = writeMessagesToStream(c, []string{msg}, fmtNewline) + require.NoError(t, err) + require.NoError(t, c.Close()) + + // Give a moment for any async processing + time.Sleep(100 * time.Millisecond) + + require.Empty(t, handler.Received(), "empty MSG should be rejected when AllowEmptyRFC5424Msg is false") +} + const layout = "Jan 02 15:04:05" var reCefDate = regexp.MustCompile(`(Dec \d{2} \d{2}:\d{2}:\d{2})`) diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index 15d98311e0f..2f029a7112e 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -22,6 +22,7 @@ type ListenerConfig struct { UseIncomingTimestamp bool `alloy:"use_incoming_timestamp,attr,optional"` UseRFC5424Message bool `alloy:"use_rfc5424_message,attr,optional"` RFC3164DefaultToCurrentYear bool `alloy:"rfc3164_default_to_current_year,attr,optional"` + AllowEmptyRFC5424Msg bool `alloy:"allow_empty_rfc5424_msg,attr,optional"` MaxMessageLength int `alloy:"max_message_length,attr,optional"` TLSConfig config.TLSConfig `alloy:"tls_config,block,optional"` SyslogFormat scrapeconfig.SyslogFormat `alloy:"syslog_format,attr,optional"` @@ -89,6 +90,12 @@ func (sc *ListenerConfig) Validate() error { } } + if sc.SyslogFormat != scrapeconfig.SyslogFormatRFC5424 { + if sc.AllowEmptyRFC5424Msg { + return fmt.Errorf(`"allow_empty_rfc5424_msg" has no effect when syslog format is set to %q`, sc.SyslogFormat) + } + } + if sc.SyslogFormat == scrapeconfig.SyslogFormatRaw { // mention fields that have no effect for better UX if sc.UseRFC5424Message { @@ -129,6 +136,7 @@ func (sc ListenerConfig) Convert() (*scrapeconfig.SyslogTargetConfig, error) { UseIncomingTimestamp: sc.UseIncomingTimestamp, UseRFC5424Message: sc.UseRFC5424Message, RFC3164DefaultToCurrentYear: sc.RFC3164DefaultToCurrentYear, + AllowEmptyRFC5424Msg: sc.AllowEmptyRFC5424Msg, MaxMessageLength: sc.MaxMessageLength, TLSConfig: *sc.TLSConfig.Convert(), SyslogFormat: sc.SyslogFormat, diff --git a/internal/component/loki/source/syslog/types_test.go b/internal/component/loki/source/syslog/types_test.go index c0a859a2d9d..7417fbd6a32 100644 --- a/internal/component/loki/source/syslog/types_test.go +++ b/internal/component/loki/source/syslog/types_test.go @@ -128,6 +128,7 @@ func TestValidateRawOnlyOpts(t *testing.T) { } mappings := map[string]*bool{ + "allow_empty_rfc5424_msg": &sc.AllowEmptyRFC5424Msg, "use_rfc5424_message": &sc.UseRFC5424Message, "rfc3164_default_to_current_year": &sc.RFC3164DefaultToCurrentYear, "use_incoming_timestamp": &sc.UseIncomingTimestamp, From 0ed65cb4ad90a2750b8ac552c8a0ed4c5aca4992 Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 13 Mar 2026 10:45:22 +0100 Subject: [PATCH 2/9] update docs --- docs/sources/reference/components/loki/loki.source.syslog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index 7753891b096..e7145836b3d 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -148,12 +148,15 @@ The `rfc3164_default_to_current_year`, `use_incoming_timestamp` and `use_rfc5424 * **`rfc3164`** A legacy syslog format, also known as BSD syslog. Example: `<34>Oct 11 22:14:15 my-server-01 sshd[1234]: Failed password for root from 192.168.1.10 port 22 ssh2` + Messages with empty MSG content are dropped and the `loki_source_syslog_empty_messages_total` counter is incremented. * **`rfc5424`** A modern, structured syslog format. Uses ISO 8601 for timestamps. Example: `<165>1 2025-12-18T00:33:00Z web01 nginx - - [audit@123 id="456"] Login failed`. + Messages with empty MSG content are dropped by default; set `allow_empty_rfc5424_msg` to `true` to forward them. The `loki_source_syslog_empty_messages_total` counter is incremented in both cases for debugging. * **`raw`** Disables log line parsing. This format allows receiving non-RFC5424 compliant logs, such as [CEF][cef]. Raw logs can be forwarded to [`loki.process`](./loki.process.md) component for parsing. + Messages with nil or empty body are dropped and the `loki_source_syslog_empty_messages_total` counter is incremented. [cef]: https://www.splunk.com/en_us/blog/learn/common-event-format-cef.html From f8bcff754dba4461f7e2102dfe82c24df77d5f83 Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:02:55 +0100 Subject: [PATCH 3/9] add explicit tests for empty messages for raw and 3164 formats --- .../syslogtarget/syslogtarget_test.go | 110 +++++++++++++++--- 1 file changed, 92 insertions(+), 18 deletions(-) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go index 15ac942dfa1..e65b0a87884 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go @@ -583,10 +583,7 @@ func TestSyslogTarget_RFC5424MessageEmptyMSGWhenAllowed(t *testing.T) { Relabel: []*relabel.Config{}, Config: &scrapeconfig.SyslogTargetConfig{ ListenAddress: "127.0.0.1:0", - ListenProtocol: ProtocolTCP, - LabelStructuredData: true, - UseRFC5424Message: true, - UseIncomingTimestamp: true, + ListenProtocol: ProtocolUDP, AllowEmptyRFC5424Msg: true, Labels: model.LabelSet{ "test": "syslog_target", @@ -600,7 +597,7 @@ func TestSyslogTarget_RFC5424MessageEmptyMSGWhenAllowed(t *testing.T) { }() addr := tgt.ListenAddress().String() - c, err := net.Dial(ProtocolTCP, addr) + c, err := net.Dial(ProtocolUDP, addr) require.NoError(t, err) err = writeMessagesToStream(c, []string{msg}, fmtNewline) @@ -612,9 +609,7 @@ func TestSyslogTarget_RFC5424MessageEmptyMSGWhenAllowed(t *testing.T) { }, time.Second, time.Millisecond, "Expected to receive 1 message, got %d.", len(handler.Received())) entry := handler.Received()[0] - require.Equal(t, msg, entry.Line, "Line should be the full RFC 5424 string when MSG part is empty") - require.NotZero(t, entry.Timestamp) - require.Equal(t, time.Date(2026, 2, 19, 14, 57, 17, 97*int(time.Millisecond), time.UTC), entry.Timestamp) + require.Equal(t, "", entry.Line, "empty MSG yields empty line when using MSG-only format") require.Equal(t, model.LabelSet{"test": "syslog_target"}, entry.Labels) } @@ -635,12 +630,8 @@ func TestSyslogTarget_RFC5424MessageEmptyMSGWhenNotAllowed(t *testing.T) { Relabel: []*relabel.Config{}, Config: &scrapeconfig.SyslogTargetConfig{ ListenAddress: "127.0.0.1:0", - ListenProtocol: ProtocolTCP, + ListenProtocol: ProtocolUDP, AllowEmptyRFC5424Msg: false, - LabelStructuredData: true, - Labels: model.LabelSet{ - "test": "syslog_target", - }, }, }) require.NoError(t, err) @@ -650,17 +641,17 @@ func TestSyslogTarget_RFC5424MessageEmptyMSGWhenNotAllowed(t *testing.T) { }() addr := tgt.ListenAddress().String() - c, err := net.Dial(ProtocolTCP, addr) + c, err := net.Dial(ProtocolUDP, addr) require.NoError(t, err) err = writeMessagesToStream(c, []string{msg}, fmtNewline) require.NoError(t, err) require.NoError(t, c.Close()) - // Give a moment for any async processing - time.Sleep(100 * time.Millisecond) - - require.Empty(t, handler.Received(), "empty MSG should be rejected when AllowEmptyRFC5424Msg is false") + start := time.Now() + require.Eventually(t, func() bool { + return time.Since(start) >= 100*time.Millisecond && len(handler.Received()) == 0 + }, 200*time.Millisecond, 10*time.Millisecond, "RFC5424 log with nil Message should be dropped when AllowEmptyRFC5424Msg is false") } const layout = "Jan 02 15:04:05" @@ -899,6 +890,89 @@ func TestSyslogTarget_CEFRawMessages(t *testing.T) { require.Equal(t, wantLines, gotLines, "log lines did not match") } +func TestSyslogTarget_RawMessageEmptyDropped(t *testing.T) { + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + handler := loki.NewCollectingHandler() + defer handler.Stop() + + metrics := NewMetrics(nil) + tgt, err := NewSyslogTarget(TargetParams{ + Metrics: metrics, + Logger: logger, + Handler: handler, + Relabel: []*relabel.Config{}, + Config: &scrapeconfig.SyslogTargetConfig{ + ListenAddress: "127.0.0.1:0", + ListenProtocol: "udp", + SyslogFormat: scrapeconfig.SyslogFormatRaw, + RawFormatOptions: scrapeconfig.RawFormatOptions{ + UseNullTerminatorDelimiter: false, + }, + }, + }) + require.NoError(t, err) + require.Eventually(t, tgt.Ready, time.Second, 10*time.Millisecond) + + addr := tgt.ListenAddress().String() + c, err := net.Dial("udp", addr) + require.NoError(t, err) + + // "<13>" has PRI only, no message content — raw parser produces empty Message + messages := []string{ + "<13>", + "<34> ", // PRI + whitespace only + } + err = writeMessagesToStream(c, messages, fmtNewline) + require.NoError(t, err) + require.NoError(t, c.Close()) + + time.Sleep(100 * time.Millisecond) + require.NoError(t, tgt.Stop()) + + require.Empty(t, handler.Received(), "raw log with nil Message should be dropped") +} + +func TestSyslogTarget_RFC3164MessageEmptyDropped(t *testing.T) { + // PRI+timestamp only — no hostname, tag, or message. Parser produces nil Message. + logLine := "<13>Dec 1 00:00:00" + + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + handler := loki.NewCollectingHandler() + defer handler.Stop() + + metrics := NewMetrics(nil) + tgt, err := NewSyslogTarget(TargetParams{ + Metrics: metrics, + Logger: logger, + Handler: handler, + Relabel: []*relabel.Config{}, + Config: &scrapeconfig.SyslogTargetConfig{ + ListenAddress: "127.0.0.1:0", + ListenProtocol: ProtocolUDP, + SyslogFormat: scrapeconfig.SyslogFormatRFC3164, + }, + }) + require.NoError(t, err) + require.Eventually(t, tgt.Ready, time.Second, 10*time.Millisecond) + defer func() { + require.NoError(t, tgt.Stop()) + }() + + addr := tgt.ListenAddress().String() + c, err := net.Dial(ProtocolUDP, addr) + require.NoError(t, err) + + err = writeMessagesToStream(c, []string{logLine}, fmtNewline) + require.NoError(t, err) + require.NoError(t, c.Close()) + + time.Sleep(100 * time.Millisecond) + + require.Empty(t, handler.Received(), "RFC3164 log with nil Message should be dropped") +} + func TestSyslogTarget_RFC3164YearSetting(t *testing.T) { for _, tt := range []struct { name string From 754c1e8ce4400794fbc3c1721d53c622c987b44d Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:28:43 +0100 Subject: [PATCH 4/9] Update docs/sources/reference/components/loki/loki.source.syslog.md Co-authored-by: Clayton Cornell <131809008+clayton-cornell@users.noreply.github.com> --- docs/sources/reference/components/loki/loki.source.syslog.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index e7145836b3d..9710c2fa135 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -152,7 +152,9 @@ The `rfc3164_default_to_current_year`, `use_incoming_timestamp` and `use_rfc5424 * **`rfc5424`** A modern, structured syslog format. Uses ISO 8601 for timestamps. Example: `<165>1 2025-12-18T00:33:00Z web01 nginx - - [audit@123 id="456"] Login failed`. - Messages with empty MSG content are dropped by default; set `allow_empty_rfc5424_msg` to `true` to forward them. The `loki_source_syslog_empty_messages_total` counter is incremented in both cases for debugging. + `loki.source.syslog` drops messages with empty MSG content by default. + Set `allow_empty_rfc5424_msg` to `true` to forward them. + `loki.source.syslog` increments the `loki_source_syslog_empty_messages_total` counter in both cases for debugging. * **`raw`** Disables log line parsing. This format allows receiving non-RFC5424 compliant logs, such as [CEF][cef]. Raw logs can be forwarded to [`loki.process`](./loki.process.md) component for parsing. From 2cb026b417f75e561ce799eae7738faa2dc89c53 Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:28:54 +0100 Subject: [PATCH 5/9] Update docs/sources/reference/components/loki/loki.source.syslog.md Co-authored-by: Clayton Cornell <131809008+clayton-cornell@users.noreply.github.com> --- docs/sources/reference/components/loki/loki.source.syslog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index 9710c2fa135..a674c8d50af 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -148,7 +148,7 @@ The `rfc3164_default_to_current_year`, `use_incoming_timestamp` and `use_rfc5424 * **`rfc3164`** A legacy syslog format, also known as BSD syslog. Example: `<34>Oct 11 22:14:15 my-server-01 sshd[1234]: Failed password for root from 192.168.1.10 port 22 ssh2` - Messages with empty MSG content are dropped and the `loki_source_syslog_empty_messages_total` counter is incremented. + `loki.source.syslog` drops messages with empty MSG content and increments the `loki_source_syslog_empty_messages_total` counter. * **`rfc5424`** A modern, structured syslog format. Uses ISO 8601 for timestamps. Example: `<165>1 2025-12-18T00:33:00Z web01 nginx - - [audit@123 id="456"] Login failed`. From c335933c013665b3ee4b0b0cd327aefd672eb7ce Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:29:16 +0100 Subject: [PATCH 6/9] Update docs/sources/reference/components/loki/loki.source.syslog.md Co-authored-by: Clayton Cornell <131809008+clayton-cornell@users.noreply.github.com> --- docs/sources/reference/components/loki/loki.source.syslog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index a674c8d50af..36c5adcbb39 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -158,7 +158,7 @@ The `rfc3164_default_to_current_year`, `use_incoming_timestamp` and `use_rfc5424 * **`raw`** Disables log line parsing. This format allows receiving non-RFC5424 compliant logs, such as [CEF][cef]. Raw logs can be forwarded to [`loki.process`](./loki.process.md) component for parsing. - Messages with nil or empty body are dropped and the `loki_source_syslog_empty_messages_total` counter is incremented. + `loki.source.syslog` drops messages with nil or empty body and increments the `loki_source_syslog_empty_messages_total` counter. [cef]: https://www.splunk.com/en_us/blog/learn/common-event-format-cef.html From 12894ee3a626ed8bdb9e587c4c4a810f9d8a47da Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:00:08 +0100 Subject: [PATCH 7/9] AllowEmptyRFC5424Msg -> RFC5424AllowEmptyMsg --- .../reference/components/loki/loki.source.syslog.md | 4 ++-- internal/component/loki/source/syslog/config/config.go | 4 ++-- .../source/syslog/internal/syslogtarget/syslogtarget.go | 2 +- .../syslog/internal/syslogtarget/syslogtarget_test.go | 6 +++--- internal/component/loki/source/syslog/types.go | 8 ++++---- internal/component/loki/source/syslog/types_test.go | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index 36c5adcbb39..4df9aa1ca3d 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -115,7 +115,7 @@ Only the `address` field is required and any omitted fields take their default v | Name | Type | Description | Default | Required | |-----------------------------------|---------------|----------------------------------------------------------------------------------------|-------------|----------| | `address` | `string` | The `` address to listen to for syslog messages. | | yes | -| `allow_empty_rfc5424_msg` | `bool` | Whether to forward RFC5424 messages with empty MSG content. When `false`, such messages are dropped. Only applies when `syslog_format` is `rfc5424`. | `false` | no | +| `rfc5424_allow_empty_msg` | `bool` | Whether to forward RFC5424 messages with empty MSG content. When `false`, such messages are dropped. Only applies when `syslog_format` is `rfc5424`. | `false` | no | | `idle_timeout` | `duration` | The idle timeout for TCP connections. | `"120s"` | no | | `label_structured_data` | `bool` | Whether to translate syslog structured data to Loki labels. | `false` | no | | `labels` | `map(string)` | The labels to associate with each received syslog record. | `{}` | no | @@ -153,7 +153,7 @@ The `rfc3164_default_to_current_year`, `use_incoming_timestamp` and `use_rfc5424 A modern, structured syslog format. Uses ISO 8601 for timestamps. Example: `<165>1 2025-12-18T00:33:00Z web01 nginx - - [audit@123 id="456"] Login failed`. `loki.source.syslog` drops messages with empty MSG content by default. - Set `allow_empty_rfc5424_msg` to `true` to forward them. + Set `rfc5424_allow_empty_msg` to `true` to forward them. `loki.source.syslog` increments the `loki_source_syslog_empty_messages_total` counter in both cases for debugging. * **`raw`** Disables log line parsing. This format allows receiving non-RFC5424 compliant logs, such as [CEF][cef]. diff --git a/internal/component/loki/source/syslog/config/config.go b/internal/component/loki/source/syslog/config/config.go index f6ced4c771f..009502570e9 100644 --- a/internal/component/loki/source/syslog/config/config.go +++ b/internal/component/loki/source/syslog/config/config.go @@ -126,8 +126,8 @@ type SyslogTargetConfig struct { // When false, the year will default to 0. RFC3164DefaultToCurrentYear bool `yaml:"rfc3164_default_to_current_year"` - // AllowEmptyRFC5424Msg when true, forwards RFC5424 messages with empty MSG content. Default false. - AllowEmptyRFC5424Msg bool `yaml:"allow_empty_rfc5424_msg"` + // RFC5424AllowEmptyMsg when true, forwards RFC5424 messages with empty MSG content. Default false. + RFC5424AllowEmptyMsg bool `yaml:"rfc5424_allow_empty_msg"` // RFC3164CiscoComponents enables and configures Cisco IOS syslog parsing. RFC3164CiscoComponents *RFC3164CiscoComponents `yaml:"rfc3164_cisco_components"` diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go index 4f9ed482507..1e96dde08ad 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go @@ -139,7 +139,7 @@ func (t *SyslogTarget) handleMessageRFC5424(connLabels labels.Labels, msg *rfc54 if msg.Message == nil { t.metrics.syslogEmptyMessages.Inc() - if !t.config.AllowEmptyRFC5424Msg { + if !t.config.RFC5424AllowEmptyMsg { return } } diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go index e65b0a87884..bd61a01ba9a 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go @@ -584,7 +584,7 @@ func TestSyslogTarget_RFC5424MessageEmptyMSGWhenAllowed(t *testing.T) { Config: &scrapeconfig.SyslogTargetConfig{ ListenAddress: "127.0.0.1:0", ListenProtocol: ProtocolUDP, - AllowEmptyRFC5424Msg: true, + RFC5424AllowEmptyMsg: true, Labels: model.LabelSet{ "test": "syslog_target", }, @@ -631,7 +631,7 @@ func TestSyslogTarget_RFC5424MessageEmptyMSGWhenNotAllowed(t *testing.T) { Config: &scrapeconfig.SyslogTargetConfig{ ListenAddress: "127.0.0.1:0", ListenProtocol: ProtocolUDP, - AllowEmptyRFC5424Msg: false, + RFC5424AllowEmptyMsg: false, }, }) require.NoError(t, err) @@ -651,7 +651,7 @@ func TestSyslogTarget_RFC5424MessageEmptyMSGWhenNotAllowed(t *testing.T) { start := time.Now() require.Eventually(t, func() bool { return time.Since(start) >= 100*time.Millisecond && len(handler.Received()) == 0 - }, 200*time.Millisecond, 10*time.Millisecond, "RFC5424 log with nil Message should be dropped when AllowEmptyRFC5424Msg is false") + }, 200*time.Millisecond, 10*time.Millisecond, "RFC5424 log with nil Message should be dropped when RFC5424AllowEmptyMsg is false") } const layout = "Jan 02 15:04:05" diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index 2f029a7112e..cc4ab659af5 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -22,7 +22,7 @@ type ListenerConfig struct { UseIncomingTimestamp bool `alloy:"use_incoming_timestamp,attr,optional"` UseRFC5424Message bool `alloy:"use_rfc5424_message,attr,optional"` RFC3164DefaultToCurrentYear bool `alloy:"rfc3164_default_to_current_year,attr,optional"` - AllowEmptyRFC5424Msg bool `alloy:"allow_empty_rfc5424_msg,attr,optional"` + RFC5424AllowEmptyMsg bool `alloy:"rfc5424_allow_empty_msg,attr,optional"` MaxMessageLength int `alloy:"max_message_length,attr,optional"` TLSConfig config.TLSConfig `alloy:"tls_config,block,optional"` SyslogFormat scrapeconfig.SyslogFormat `alloy:"syslog_format,attr,optional"` @@ -91,8 +91,8 @@ func (sc *ListenerConfig) Validate() error { } if sc.SyslogFormat != scrapeconfig.SyslogFormatRFC5424 { - if sc.AllowEmptyRFC5424Msg { - return fmt.Errorf(`"allow_empty_rfc5424_msg" has no effect when syslog format is set to %q`, sc.SyslogFormat) + if sc.RFC5424AllowEmptyMsg { + return fmt.Errorf(`"rfc5424_allow_empty_msg" has no effect when syslog format is set to %q`, sc.SyslogFormat) } } @@ -136,7 +136,7 @@ func (sc ListenerConfig) Convert() (*scrapeconfig.SyslogTargetConfig, error) { UseIncomingTimestamp: sc.UseIncomingTimestamp, UseRFC5424Message: sc.UseRFC5424Message, RFC3164DefaultToCurrentYear: sc.RFC3164DefaultToCurrentYear, - AllowEmptyRFC5424Msg: sc.AllowEmptyRFC5424Msg, + RFC5424AllowEmptyMsg: sc.RFC5424AllowEmptyMsg, MaxMessageLength: sc.MaxMessageLength, TLSConfig: *sc.TLSConfig.Convert(), SyslogFormat: sc.SyslogFormat, diff --git a/internal/component/loki/source/syslog/types_test.go b/internal/component/loki/source/syslog/types_test.go index 7417fbd6a32..4465b32c347 100644 --- a/internal/component/loki/source/syslog/types_test.go +++ b/internal/component/loki/source/syslog/types_test.go @@ -128,7 +128,7 @@ func TestValidateRawOnlyOpts(t *testing.T) { } mappings := map[string]*bool{ - "allow_empty_rfc5424_msg": &sc.AllowEmptyRFC5424Msg, + "rfc5424_allow_empty_msg": &sc.RFC5424AllowEmptyMsg, "use_rfc5424_message": &sc.UseRFC5424Message, "rfc3164_default_to_current_year": &sc.RFC3164DefaultToCurrentYear, "use_incoming_timestamp": &sc.UseIncomingTimestamp, From 7037cda2b6d48f45f0ec79541a9f04206f8dc1dd Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:00:58 +0100 Subject: [PATCH 8/9] Update docs/sources/reference/components/loki/loki.source.syslog.md Co-authored-by: Denys Sedchenko <9203548+x1unix@users.noreply.github.com> --- docs/sources/reference/components/loki/loki.source.syslog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index 4df9aa1ca3d..2af5ad8d477 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -147,7 +147,7 @@ The `rfc3164_default_to_current_year`, `use_incoming_timestamp` and `use_rfc5424 * **`rfc3164`** A legacy syslog format, also known as BSD syslog. - Example: `<34>Oct 11 22:14:15 my-server-01 sshd[1234]: Failed password for root from 192.168.1.10 port 22 ssh2` + Example: `<34>Oct 11 22:14:15 my-server-01 sshd[1234]: Failed password for root from 192.168.1.10 port 22 ssh2`. `loki.source.syslog` drops messages with empty MSG content and increments the `loki_source_syslog_empty_messages_total` counter. * **`rfc5424`** A modern, structured syslog format. Uses ISO 8601 for timestamps. From e8a6d4aaf86d5726cdbf72b75ef637c99394c85f Mon Sep 17 00:00:00 2001 From: Bejal Lewis <164711649+blewis12@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:01:40 +0100 Subject: [PATCH 9/9] Update docs/sources/reference/components/loki/loki.source.syslog.md Co-authored-by: Denys Sedchenko <9203548+x1unix@users.noreply.github.com> --- .../components/loki/loki.source.syslog.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index 2af5ad8d477..2bf5214e3a1 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -112,13 +112,14 @@ The `listener` block defines the listen address and protocol where the listener The following arguments can be used to configure a `listener`. Only the `address` field is required and any omitted fields take their default values. -| Name | Type | Description | Default | Required | -|-----------------------------------|---------------|----------------------------------------------------------------------------------------|-------------|----------| -| `address` | `string` | The `` address to listen to for syslog messages. | | yes | -| `rfc5424_allow_empty_msg` | `bool` | Whether to forward RFC5424 messages with empty MSG content. When `false`, such messages are dropped. Only applies when `syslog_format` is `rfc5424`. | `false` | no | -| `idle_timeout` | `duration` | The idle timeout for TCP connections. | `"120s"` | no | -| `label_structured_data` | `bool` | Whether to translate syslog structured data to Loki labels. | `false` | no | -| `labels` | `map(string)` | The labels to associate with each received syslog record. | `{}` | no | +| Name | Type | Description | Default | Required | +|---------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------|----------|----------| +| `address` | `string` | The `` address to listen to for syslog messages. | | yes | +| `allow_empty_rfc5424_msg` | `bool` | Whether to forward RFC5424 messages with empty MSG content. When `false`, such messages are dropped. Only applies when `syslog_format` is `rfc5424`. | `false` | no | +| `idle_timeout` | `duration` | The idle timeout for TCP connections. | `"120s"` | no | +| `label_structured_data` | `bool` | Whether to translate syslog structured data to Loki labels. | `false` | no | +| `labels` | `map(string)` | The labels to associate with each received syslog record. | `{}` | no | + | `max_message_length` | `int` | The maximum limit to the length of syslog messages. | `8192` | no | | `protocol` | `string` | The protocol to listen to for syslog messages. Must be either `tcp` or `udp`. | `"tcp"` | no | | `rfc3164_default_to_current_year` | `bool` | Whether to default the incoming timestamp of an `rfc3164` message to the current year. | `false` | no |