From 39e24bb68f04e022f7297adaadce6cf74eeff4d9 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Wed, 31 Dec 2025 00:59:14 -0500 Subject: [PATCH 01/20] feat: add cisco components to component args --- .../loki/source/syslog/config/config.go | 12 +++++ .../component/loki/source/syslog/types.go | 47 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/internal/component/loki/source/syslog/config/config.go b/internal/component/loki/source/syslog/config/config.go index 037d9c13443..2af24ac7548 100644 --- a/internal/component/loki/source/syslog/config/config.go +++ b/internal/component/loki/source/syslog/config/config.go @@ -55,6 +55,15 @@ func (s SyslogFormat) Validate() error { return fmt.Errorf("unknown syslog format: %q", s) } +// RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. +type RFC3164CiscoComponents struct { + EnableAllComponents bool + DisableMessageCounter bool + DisableSequenceNumber bool + DisableHostname bool + DisableSecondFractions bool +} + // RawFormatOptions are options for raw syslog format processing. type RawFormatOptions struct { // UseNullTerminatorDelimiter sets null terminator ('\0') as a log line delimiter for non-transparent framed messages. @@ -116,6 +125,9 @@ type SyslogTargetConfig struct { // When parsing an RFC3164 message, should the year be defaulted to the current year? // When false, the year will default to 0. RFC3164DefaultToCurrentYear bool `yaml:"rfc3164_default_to_current_year"` + + // RFC3164CiscoComponents enables and configures Cisco IOS syslog parsing. + RFC3164CiscoComponents *RFC3164CiscoComponents `yaml:"rfc3164_cisco_components"` } func (config SyslogTargetConfig) IsRFC3164Message() bool { diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index 2d53b7ea205..628ec1deb64 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -1,6 +1,7 @@ package syslog import ( + "errors" "fmt" "time" @@ -25,6 +26,7 @@ type ListenerConfig struct { TLSConfig config.TLSConfig `alloy:"tls_config,block,optional"` SyslogFormat scrapeconfig.SyslogFormat `alloy:"syslog_format,attr,optional"` RawFormatOptions *RawFormatOptions `alloy:"raw_format_options,block,optional"` + RFC3164CiscoComponents *RFC3164CiscoComponents `alloy:"rfc3164_cisco_components,block,optional"` } // RawFormatOptions is alloy syntax mapping to [scrapeconfig.RawFormatOptions] struct. @@ -32,6 +34,31 @@ type RawFormatOptions struct { UseNullTerminatorDelimiter bool `alloy:"use_null_terminator_delimiter,attr,optional"` } +// RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. +type RFC3164CiscoComponents struct { + EnableAllComponents bool `alloy:"enable_all_components"` + DisableMessageCounter bool `alloy:"disable_message_counter"` + DisableSequenceNumber bool `alloy:"disable_sequence_number"` + DisableHostname bool `alloy:"disable_hostname"` + DisableSecondFractions bool `alloy:"disable_second_fractions"` +} + +func (sc *RFC3164CiscoComponents) Validate() error { + if sc == nil { + return nil + } + + if !sc.EnableAllComponents && + !sc.DisableHostname && + !sc.DisableMessageCounter && + !sc.DisableSecondFractions && + !sc.DisableSequenceNumber { + return errors.New("all rfc3164_cisco_components fields are empty") + } + + return nil +} + // DefaultListenerConfig provides the default arguments for a syslog listener. var DefaultListenerConfig = ListenerConfig{ ListenProtocol: st.DefaultProtocol, @@ -55,6 +82,16 @@ func (sc *ListenerConfig) Validate() error { return err } + if sc.RFC3164CiscoComponents != nil { + if sc.SyslogFormat != scrapeconfig.SyslogFormatRFC3164 { + return fmt.Errorf("rfc3164_cisco_components has no effect when syslog format is not %q", scrapeconfig.SyslogFormatRFC3164) + } + + if err := sc.RFC3164CiscoComponents.Validate(); err != nil { + return err + } + } + if sc.SyslogFormat == scrapeconfig.SyslogFormatRaw { // mention fields that have no effect for better UX if sc.UseRFC5424Message { @@ -106,5 +143,15 @@ func (sc ListenerConfig) Convert() (*scrapeconfig.SyslogTargetConfig, error) { } } + if cmp := sc.RFC3164CiscoComponents; cmp != nil { + cfg.RFC3164CiscoComponents = &scrapeconfig.RFC3164CiscoComponents{ + EnableAllComponents: cmp.EnableAllComponents, + DisableMessageCounter: cmp.DisableMessageCounter, + DisableSequenceNumber: cmp.DisableSequenceNumber, + DisableHostname: cmp.DisableHostname, + DisableSecondFractions: cmp.DisableSecondFractions, + } + } + return cfg, nil } From e003ba821a28b32c837cecc03735f48ee977b357 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Wed, 31 Dec 2025 01:16:11 -0500 Subject: [PATCH 02/20] feat: move parse args to options --- .../syslogtarget/syslogparser/syslogparser.go | 25 +++++++++++++------ .../syslogparser/syslogparser_test.go | 16 ++++++------ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go index 8616b176241..b795ab7795e 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go @@ -7,6 +7,7 @@ import ( "time" "github.com/leodido/go-syslog/v4" + "github.com/leodido/go-syslog/v4/ciscoios" "github.com/leodido/go-syslog/v4/nontransparent" "github.com/leodido/go-syslog/v4/octetcounting" "github.com/leodido/go-syslog/v4/rfc3164" @@ -46,11 +47,19 @@ func isDigit(b byte) bool { return b >= '0' && b <= '9' } +type StreamParseConfig struct { + MaxMessageLength int + IsRFC3164Message bool + UseRFC3164DefaultYear bool + RFC3164CiscoEnabled bool + RFC3164CiscoComponents ciscoios.Component +} + // ParseStream parses a rfc5424 syslog stream from the given Reader, calling // the callback function with the parsed messages. The parser automatically // detects octet counting. // The function returns on EOF or unrecoverable errors. -func ParseStream(isRFC3164Message bool, useRFC3164DefaultYear bool, r io.Reader, callback func(res *syslog.Result), maxMessageLength int) error { +func ParseStream(cfg StreamParseConfig, r io.Reader, callback func(res *syslog.Result)) error { buf := bufio.NewReaderSize(r, 1<<10) b, err := buf.ReadByte() @@ -59,7 +68,7 @@ func ParseStream(isRFC3164Message bool, useRFC3164DefaultYear bool, r io.Reader, } _ = buf.UnreadByte() cb := callback - if isRFC3164Message && useRFC3164DefaultYear { + if cfg.IsRFC3164Message && cfg.UseRFC3164DefaultYear { cb = func(res *syslog.Result) { if res.Message != nil { rfc3164Msg := res.Message.(*rfc3164.SyslogMessage) @@ -76,17 +85,17 @@ func ParseStream(isRFC3164Message bool, useRFC3164DefaultYear bool, r io.Reader, // an explicit framing character. switch framingTypeFromFirstByte(b) { case framingTypeNonTransparent: - if isRFC3164Message { - nontransparent.NewParserRFC3164(syslog.WithListener(cb), syslog.WithMaxMessageLength(maxMessageLength), syslog.WithBestEffort()).Parse(buf) + if cfg.IsRFC3164Message { + nontransparent.NewParserRFC3164(syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort()).Parse(buf) } else { - nontransparent.NewParser(syslog.WithListener(cb), syslog.WithMaxMessageLength(maxMessageLength), syslog.WithBestEffort()).Parse(buf) + nontransparent.NewParser(syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort()).Parse(buf) } case framingTypeOctetCounting: // If a syslog message starts with a digit, it must use octet counting, and the first piece of the message is the length - if isRFC3164Message { - octetcounting.NewParserRFC3164(syslog.WithListener(cb), syslog.WithMaxMessageLength(maxMessageLength), syslog.WithBestEffort()).Parse(buf) + if cfg.IsRFC3164Message { + octetcounting.NewParserRFC3164(syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort()).Parse(buf) } else { - octetcounting.NewParser(syslog.WithListener(cb), syslog.WithMaxMessageLength(maxMessageLength), syslog.WithBestEffort()).Parse(buf) + octetcounting.NewParser(syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort()).Parse(buf) } default: return fmt.Errorf("invalid or unsupported framing. first byte: %q", b) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser_test.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser_test.go index ac8009b0129..81c619a117f 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser_test.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser_test.go @@ -26,7 +26,7 @@ func TestParseStream_OctetCounting(t *testing.T) { results = append(results, res) } - err := syslogparser.ParseStream(false, false, r, cb, defaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{MaxMessageLength: defaultMaxMessageLength}, r, cb) require.NoError(t, err) require.Equal(t, 2, len(results)) @@ -45,7 +45,7 @@ func TestParseStream_ValidParseError(t *testing.T) { results = append(results, res) } - err := syslogparser.ParseStream(false, false, r, cb, defaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{MaxMessageLength: defaultMaxMessageLength}, r, cb) require.NoError(t, err) require.Equal(t, 1, len(results)) @@ -61,7 +61,7 @@ func TestParseStream_OctetCounting_LongMessage(t *testing.T) { results = append(results, res) } - err := syslogparser.ParseStream(false, false, r, cb, defaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{MaxMessageLength: defaultMaxMessageLength}, r, cb) require.NoError(t, err) require.Equal(t, 1, len(results)) @@ -76,7 +76,7 @@ func TestParseStream_NewlineSeparated(t *testing.T) { results = append(results, res) } - err := syslogparser.ParseStream(false, false, r, cb, defaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{MaxMessageLength: defaultMaxMessageLength}, r, cb) require.NoError(t, err) require.Equal(t, 2, len(results)) @@ -89,14 +89,14 @@ func TestParseStream_NewlineSeparated(t *testing.T) { func TestParseStream_InvalidStream(t *testing.T) { r := strings.NewReader("invalid") - err := syslogparser.ParseStream(false, false, r, func(_ *syslog.Result) {}, defaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{MaxMessageLength: defaultMaxMessageLength}, r, func(_ *syslog.Result) {}) require.EqualError(t, err, "invalid or unsupported framing. first byte: 'i'") } func TestParseStream_EmptyStream(t *testing.T) { r := strings.NewReader("") - err := syslogparser.ParseStream(false, false, r, func(_ *syslog.Result) {}, defaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{MaxMessageLength: defaultMaxMessageLength}, r, func(_ *syslog.Result) {}) require.Equal(t, err, io.EOF) } @@ -108,7 +108,7 @@ func TestParseStream_RFC3164Timestamp(t *testing.T) { results = append(results, res) } - err := syslogparser.ParseStream(true, false, r, cb, defaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{MaxMessageLength: defaultMaxMessageLength, IsRFC3164Message: true}, r, cb) require.NoError(t, err) require.Equal(t, 1, len(results)) @@ -126,7 +126,7 @@ func TestParseStream_RFC3164TimestampWithYear(t *testing.T) { results = append(results, res) } - err := syslogparser.ParseStream(true, true, r, cb, defaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{MaxMessageLength: defaultMaxMessageLength, IsRFC3164Message: true, UseRFC3164DefaultYear: true}, r, cb) require.NoError(t, err) require.Equal(t, 1, len(results)) From be76678c5a0cbb9e42e536ad23f397e397d6f4f3 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Wed, 31 Dec 2025 01:36:17 -0500 Subject: [PATCH 03/20] feat: decouple parser selection and parsing --- .../syslogtarget/syslogparser/syslogparser.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go index b795ab7795e..6b3b39098d2 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go @@ -83,23 +83,31 @@ func ParseStream(cfg StreamParseConfig, r io.Reader, callback func(res *syslog.R // See https://datatracker.ietf.org/doc/html/rfc6587 for details on message framing // If a syslog message starts with '<' the first piece of the message is the priority, which means it must use // an explicit framing character. + opts := []syslog.ParserOption{ + syslog.WithListener(cb), + syslog.WithMaxMessageLength(cfg.MaxMessageLength), + syslog.WithBestEffort(), + } + + var parserFunc func(args ...syslog.ParserOption) syslog.Parser switch framingTypeFromFirstByte(b) { case framingTypeNonTransparent: if cfg.IsRFC3164Message { - nontransparent.NewParserRFC3164(syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort()).Parse(buf) + parserFunc = nontransparent.NewParserRFC3164 } else { - nontransparent.NewParser(syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort()).Parse(buf) + parserFunc = nontransparent.NewParser } case framingTypeOctetCounting: // If a syslog message starts with a digit, it must use octet counting, and the first piece of the message is the length if cfg.IsRFC3164Message { - octetcounting.NewParserRFC3164(syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort()).Parse(buf) + parserFunc = octetcounting.NewParserRFC3164 } else { - octetcounting.NewParser(syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort()).Parse(buf) + parserFunc = octetcounting.NewParser } default: return fmt.Errorf("invalid or unsupported framing. first byte: %q", b) } + parserFunc(opts...).Parse(r) return nil } From fdba9d789f76c2c93f0617d872c6b8c208bb46fa Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Wed, 31 Dec 2025 02:50:07 -0500 Subject: [PATCH 04/20] feat: add cisco opts --- .../syslogtarget/syslogparser/syslogparser.go | 48 ++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go index 6b3b39098d2..25e092b4f31 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go @@ -7,7 +7,6 @@ import ( "time" "github.com/leodido/go-syslog/v4" - "github.com/leodido/go-syslog/v4/ciscoios" "github.com/leodido/go-syslog/v4/nontransparent" "github.com/leodido/go-syslog/v4/octetcounting" "github.com/leodido/go-syslog/v4/rfc3164" @@ -47,12 +46,44 @@ func isDigit(b byte) bool { return b >= '0' && b <= '9' } +type RFC3164CiscoComponents struct { + MessageCounter bool + SequenceNumber bool + CiscoHostname bool + SecondFractions bool +} + type StreamParseConfig struct { MaxMessageLength int IsRFC3164Message bool UseRFC3164DefaultYear bool - RFC3164CiscoEnabled bool - RFC3164CiscoComponents ciscoios.Component + RFC3164CiscoComponents *RFC3164CiscoComponents +} + +func (cfg StreamParseConfig) ciscoComponentOptions() []syslog.MachineOption { + cmps := cfg.RFC3164CiscoComponents + if cmps == nil { + return nil + } + + opts := make([]syslog.MachineOption, 0, 4) // max number of cisco components + if cmps.MessageCounter { + opts = append(opts, rfc3164.WithMessageCounter()) + } + + if cmps.SequenceNumber { + opts = append(opts, rfc3164.WithSequenceNumber()) + } + + if cmps.CiscoHostname { + opts = append(opts, rfc3164.WithCiscoHostname()) + } + + if cmps.SecondFractions { + opts = append(opts, rfc3164.WithSecondFractions()) + } + + return opts } // ParseStream parses a rfc5424 syslog stream from the given Reader, calling @@ -80,15 +111,20 @@ func ParseStream(cfg StreamParseConfig, r io.Reader, callback func(res *syslog.R } } - // See https://datatracker.ietf.org/doc/html/rfc6587 for details on message framing - // If a syslog message starts with '<' the first piece of the message is the priority, which means it must use - // an explicit framing character. opts := []syslog.ParserOption{ syslog.WithListener(cb), syslog.WithMaxMessageLength(cfg.MaxMessageLength), syslog.WithBestEffort(), } + if cfg.IsRFC3164Message && cfg.RFC3164CiscoComponents != nil { + machineOpts := cfg.ciscoComponentOptions() + opts = append(opts, syslog.WithMachineOptions(machineOpts...)) + } + + // See https://datatracker.ietf.org/doc/html/rfc6587 for details on message framing + // If a syslog message starts with '<' the first piece of the message is the priority, which means it must use + // an explicit framing character. var parserFunc func(args ...syslog.ParserOption) syslog.Parser switch framingTypeFromFirstByte(b) { case framingTypeNonTransparent: From 29a5bebaa16b8bf8f0090af3b5b2035d9546f5b7 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Wed, 31 Dec 2025 14:42:01 -0500 Subject: [PATCH 05/20] feat: map cisco options --- .../loki/source/syslog/config/config.go | 10 +++--- .../syslog/internal/syslogtarget/transport.go | 32 ++++++++++++++----- .../component/loki/source/syslog/types.go | 29 ++++++++--------- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/internal/component/loki/source/syslog/config/config.go b/internal/component/loki/source/syslog/config/config.go index 2af24ac7548..0eb134a76d0 100644 --- a/internal/component/loki/source/syslog/config/config.go +++ b/internal/component/loki/source/syslog/config/config.go @@ -57,11 +57,11 @@ func (s SyslogFormat) Validate() error { // RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. type RFC3164CiscoComponents struct { - EnableAllComponents bool - DisableMessageCounter bool - DisableSequenceNumber bool - DisableHostname bool - DisableSecondFractions bool + EnableAllComponents bool + MessageCounter bool + SequenceNumber bool + Hostname bool + SecondFractions bool } // RawFormatOptions are options for raw syslog format processing. diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/transport.go b/internal/component/loki/source/syslog/internal/syslogtarget/transport.go index d45999a8f39..784fc149956 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/transport.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/transport.go @@ -85,6 +85,26 @@ func (t *baseTransport) maxMessageLength() int { return DefaultMaxMessageLength } +func (t *baseTransport) streamParseConfig() syslogparser.StreamParseConfig { + ciscoCfg := t.config.RFC3164CiscoComponents + parseCfg := syslogparser.StreamParseConfig{ + MaxMessageLength: t.maxMessageLength(), + IsRFC3164Message: t.config.IsRFC3164Message(), + UseRFC3164DefaultYear: t.config.RFC3164DefaultToCurrentYear, + } + + if ciscoCfg != nil { + parseCfg.RFC3164CiscoComponents = &syslogparser.RFC3164CiscoComponents{ + MessageCounter: ciscoCfg.EnableAllComponents || ciscoCfg.MessageCounter, + SequenceNumber: ciscoCfg.EnableAllComponents || ciscoCfg.SequenceNumber, + CiscoHostname: ciscoCfg.EnableAllComponents || ciscoCfg.Hostname, + SecondFractions: ciscoCfg.EnableAllComponents || ciscoCfg.SecondFractions, + } + } + + return parseCfg +} + func (t *baseTransport) connectionLabels(ip string) labels.Labels { lb := labels.NewBuilder(labels.EmptyLabels()) for k, v := range t.config.Labels { @@ -346,7 +366,8 @@ func (t *TCPTransport) handleConnection(cn net.Conn) { return } - err := syslogparser.ParseStream(t.config.IsRFC3164Message(), t.config.RFC3164DefaultToCurrentYear, c, cb, t.maxMessageLength()) + parseCfg := t.streamParseConfig() + err := syslogparser.ParseStream(parseCfg, c, cb) if err != nil { if errors.Is(err, io.EOF) { level.Debug(t.logger).Log("msg", "syslog connection closed", "remote", c.RemoteAddr().String()) @@ -486,13 +507,8 @@ func (t *UDPTransport) handleRcv(c *ConnPipe) { continue } - err = syslogparser.ParseStream(t.config.IsRFC3164Message(), t.config.RFC3164DefaultToCurrentYear, r, func(result *syslog.Result) { - if err := result.Error; err != nil { - t.handleMessageError(err) - } else { - t.handleMessage(lbs.Copy(), result.Message) - } - }, t.maxMessageLength()) + parseCfg := t.streamParseConfig() + err = syslogparser.ParseStream(parseCfg, r, cb) if err != nil { level.Warn(t.logger).Log("msg", "error parsing syslog stream", "err", err) } diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index 628ec1deb64..01703095099 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -36,11 +36,11 @@ type RawFormatOptions struct { // RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. type RFC3164CiscoComponents struct { - EnableAllComponents bool `alloy:"enable_all_components"` - DisableMessageCounter bool `alloy:"disable_message_counter"` - DisableSequenceNumber bool `alloy:"disable_sequence_number"` - DisableHostname bool `alloy:"disable_hostname"` - DisableSecondFractions bool `alloy:"disable_second_fractions"` + EnableAllComponents bool `alloy:"enable_all_components"` + MessageCounter bool `alloy:"disable_message_counter"` + SequenceNumber bool `alloy:"disable_sequence_number"` + Hostname bool `alloy:"disable_hostname"` + SecondFractions bool `alloy:"disable_second_fractions"` } func (sc *RFC3164CiscoComponents) Validate() error { @@ -48,12 +48,9 @@ func (sc *RFC3164CiscoComponents) Validate() error { return nil } - if !sc.EnableAllComponents && - !sc.DisableHostname && - !sc.DisableMessageCounter && - !sc.DisableSecondFractions && - !sc.DisableSequenceNumber { - return errors.New("all rfc3164_cisco_components fields are empty") + isEmpty := !sc.EnableAllComponents && !sc.Hostname && !sc.MessageCounter && !sc.SecondFractions && !sc.SequenceNumber + if isEmpty { + return errors.New("at least one option in rfc3164_cisco_components has to be enabled") } return nil @@ -145,11 +142,11 @@ func (sc ListenerConfig) Convert() (*scrapeconfig.SyslogTargetConfig, error) { if cmp := sc.RFC3164CiscoComponents; cmp != nil { cfg.RFC3164CiscoComponents = &scrapeconfig.RFC3164CiscoComponents{ - EnableAllComponents: cmp.EnableAllComponents, - DisableMessageCounter: cmp.DisableMessageCounter, - DisableSequenceNumber: cmp.DisableSequenceNumber, - DisableHostname: cmp.DisableHostname, - DisableSecondFractions: cmp.DisableSecondFractions, + EnableAllComponents: cmp.EnableAllComponents, + MessageCounter: cmp.MessageCounter, + SequenceNumber: cmp.SequenceNumber, + Hostname: cmp.Hostname, + SecondFractions: cmp.SecondFractions, } } From 79c7018618f6fccca3c4db8d0bd052226165aab9 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Wed, 31 Dec 2025 16:35:15 -0500 Subject: [PATCH 06/20] feat: add arguments test --- .../component/loki/source/syslog/types.go | 16 ++--- .../loki/source/syslog/types_test.go | 63 +++++++++++++++++++ 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index 01703095099..af4be74434e 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -36,19 +36,19 @@ type RawFormatOptions struct { // RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. type RFC3164CiscoComponents struct { - EnableAllComponents bool `alloy:"enable_all_components"` - MessageCounter bool `alloy:"disable_message_counter"` - SequenceNumber bool `alloy:"disable_sequence_number"` - Hostname bool `alloy:"disable_hostname"` - SecondFractions bool `alloy:"disable_second_fractions"` + EnableAll bool `alloy:"enable_all"` + MessageCounter bool `alloy:"message_counter"` + SequenceNumber bool `alloy:"sequence_number"` + Hostname bool `alloy:"hostname"` + SecondFractions bool `alloy:"second_fractions"` } func (sc *RFC3164CiscoComponents) Validate() error { - if sc == nil { + if sc == nil || sc.EnableAll { return nil } - isEmpty := !sc.EnableAllComponents && !sc.Hostname && !sc.MessageCounter && !sc.SecondFractions && !sc.SequenceNumber + isEmpty := !sc.Hostname && !sc.MessageCounter && !sc.SecondFractions && !sc.SequenceNumber if isEmpty { return errors.New("at least one option in rfc3164_cisco_components has to be enabled") } @@ -142,7 +142,7 @@ func (sc ListenerConfig) Convert() (*scrapeconfig.SyslogTargetConfig, error) { if cmp := sc.RFC3164CiscoComponents; cmp != nil { cfg.RFC3164CiscoComponents = &scrapeconfig.RFC3164CiscoComponents{ - EnableAllComponents: cmp.EnableAllComponents, + EnableAllComponents: cmp.EnableAll, MessageCounter: cmp.MessageCounter, SequenceNumber: cmp.SequenceNumber, Hostname: cmp.Hostname, diff --git a/internal/component/loki/source/syslog/types_test.go b/internal/component/loki/source/syslog/types_test.go index 20b544e97d3..c0a859a2d9d 100644 --- a/internal/component/loki/source/syslog/types_test.go +++ b/internal/component/loki/source/syslog/types_test.go @@ -1,12 +1,14 @@ package syslog import ( + "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/grafana/alloy/internal/component/loki/source/syslog/config" + "github.com/grafana/alloy/internal/loki/promtail/scrapeconfig" ) func TestValidate(t *testing.T) { @@ -57,6 +59,67 @@ func TestValidate(t *testing.T) { } } +func TestValidateCiscoComponents(t *testing.T) { + cases := []struct { + label string + cfg *ListenerConfig + errSubstring string + }{ + { + label: "cisco components require rfc3164 format", + errSubstring: fmt.Sprintf("rfc3164_cisco_components has no effect when syslog format is not %q", scrapeconfig.SyslogFormatRFC3164), + cfg: &ListenerConfig{ + SyslogFormat: scrapeconfig.SyslogFormatRFC5424, + ListenProtocol: "udp", + RFC3164CiscoComponents: &RFC3164CiscoComponents{}, + }, + }, + { + label: "at least one component should be enabled", + errSubstring: "at least one option in rfc3164_cisco_components has to be enabled", + cfg: &ListenerConfig{ + SyslogFormat: scrapeconfig.SyslogFormatRFC3164, + ListenProtocol: "udp", + RFC3164CiscoComponents: &RFC3164CiscoComponents{}, + }, + }, + { + label: "valid when all components are enabled", + cfg: &ListenerConfig{ + SyslogFormat: scrapeconfig.SyslogFormatRFC3164, + ListenProtocol: "udp", + RFC3164CiscoComponents: &RFC3164CiscoComponents{ + EnableAll: true, + }, + }, + }, + { + label: "valid when any component is enabled", + cfg: &ListenerConfig{ + SyslogFormat: scrapeconfig.SyslogFormatRFC3164, + ListenProtocol: "udp", + RFC3164CiscoComponents: &RFC3164CiscoComponents{ + MessageCounter: true, + Hostname: true, + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.label, func(t *testing.T) { + t.Parallel() + err := tc.cfg.Validate() + if tc.errSubstring == "" { + require.NoError(t, err) + return + } + + require.ErrorContains(t, err, tc.errSubstring) + }) + } +} + func TestValidateRawOnlyOpts(t *testing.T) { t.Run("RFCFieldsWithNoEffect", func(t *testing.T) { sc := &ListenerConfig{ From b933c759b3ecb7f20f43aaa07b841404a953b18c Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Wed, 31 Dec 2025 16:43:05 -0500 Subject: [PATCH 07/20] feat: align component field name with others --- internal/component/loki/source/syslog/config/config.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/component/loki/source/syslog/config/config.go b/internal/component/loki/source/syslog/config/config.go index 0eb134a76d0..3d06263ef62 100644 --- a/internal/component/loki/source/syslog/config/config.go +++ b/internal/component/loki/source/syslog/config/config.go @@ -57,11 +57,11 @@ func (s SyslogFormat) Validate() error { // RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. type RFC3164CiscoComponents struct { - EnableAllComponents bool - MessageCounter bool - SequenceNumber bool - Hostname bool - SecondFractions bool + EnableAll bool + MessageCounter bool + SequenceNumber bool + Hostname bool + SecondFractions bool } // RawFormatOptions are options for raw syslog format processing. From 12fc1f4c6841bbec4fb648f2c347de7d0056098a Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Wed, 31 Dec 2025 17:22:33 -0500 Subject: [PATCH 08/20] wip: cisco component testing --- .../syslogtarget/syslogtarget_test.go | 90 ++++++++++++++++++- .../syslog/internal/syslogtarget/transport.go | 8 +- 2 files changed, 93 insertions(+), 5 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 6c307fed93f..136f2ee4a08 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go @@ -27,6 +27,8 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" + "github.com/grafana/loki/pkg/push" + "github.com/grafana/alloy/internal/component/common/loki" scrapeconfig "github.com/grafana/alloy/internal/component/loki/source/syslog/config" "github.com/grafana/alloy/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser" @@ -590,6 +592,88 @@ func parseCefLogLines(t *testing.T, lines iter.Seq[string]) []cefLogLine { return out } +func TestSyslogTarget_RFC3136CiscoComponents(t *testing.T) { + currentYear := time.Now().Year() + parseDate := func(layout, value string) time.Time { + r, err := time.Parse(layout, value) + require.NoError(t, err, "failed to parse date") + return r.AddDate(currentYear, 0, 0) + } + + cases := []struct { + label string + logLine string + expect loki.Entry + ciscoComponents scrapeconfig.RFC3164CiscoComponents + }{ + { + label: "all components", + logLine: "<189>643: *Jan 8 19:46:03.295: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback100, changed state to up", + ciscoComponents: scrapeconfig.RFC3164CiscoComponents{ + EnableAll: true, + }, + expect: loki.Entry{ + Labels: model.LabelSet{ + "__syslog_message_severity": "notice", + "__syslog_message_facility": "local7", + "__syslog_message_app_name": "%LINEPROTO-5-UPDOWN", + }, + Entry: push.Entry{ + Timestamp: parseDate(time.StampMilli, "Jan 8 19:46:03.295"), + Line: "Line protocol on Interface Loopback100, changed state to up", + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.label, func(t *testing.T) { + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + handler := loki.NewCollectingHandler() + defer handler.Stop() + + metrics := NewMetrics(nil) + tgt, err := NewSyslogTarget(metrics, logger, handler, []*relabel.Config{}, &scrapeconfig.SyslogTargetConfig{ + ListenAddress: "127.0.0.1:0", + ListenProtocol: "udp", + LabelStructuredData: true, + SyslogFormat: scrapeconfig.SyslogFormatRFC3164, + RFC3164CiscoComponents: &tc.ciscoComponents, + RFC3164DefaultToCurrentYear: true, + Labels: model.LabelSet{ + "test": "syslog_target", + }, + }) + + 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) + + _, err = fmt.Fprintln(c, tc.logLine) + require.NoError(t, err) + require.NoError(t, c.Close()) + + time.Sleep(time.Second) + require.NoError(t, tgt.Stop()) + + require.Eventually(t, func() bool { + return len(handler.Received()) > 0 + }, time.Second, 10*time.Millisecond, "handler didn't receive any message") + + // TODO: cmp messages + received := handler.Received() + require.NotEmpty(t, received) + + msg := received[0] + t.Logf("%#v", msg) + }) + } +} + func TestSyslogTarget_CEFRawMessages(t *testing.T) { messages := []string{ `Dec 17 12:23:16 Dream-Router CEF:0|Ubiquiti`, @@ -1097,7 +1181,11 @@ func TestParseStream_WithAsyncPipe(t *testing.T) { results = append(results, res) } - err := syslogparser.ParseStream(false, false, pipe, cb, DefaultMaxMessageLength) + err := syslogparser.ParseStream(syslogparser.StreamParseConfig{ + MaxMessageLength: DefaultMaxMessageLength, + IsRFC3164Message: false, + UseRFC3164DefaultYear: false, + }, pipe, cb) require.NoError(t, err) require.Equal(t, 3, len(results)) } diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/transport.go b/internal/component/loki/source/syslog/internal/syslogtarget/transport.go index 784fc149956..e6adfb745c0 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/transport.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/transport.go @@ -95,10 +95,10 @@ func (t *baseTransport) streamParseConfig() syslogparser.StreamParseConfig { if ciscoCfg != nil { parseCfg.RFC3164CiscoComponents = &syslogparser.RFC3164CiscoComponents{ - MessageCounter: ciscoCfg.EnableAllComponents || ciscoCfg.MessageCounter, - SequenceNumber: ciscoCfg.EnableAllComponents || ciscoCfg.SequenceNumber, - CiscoHostname: ciscoCfg.EnableAllComponents || ciscoCfg.Hostname, - SecondFractions: ciscoCfg.EnableAllComponents || ciscoCfg.SecondFractions, + MessageCounter: ciscoCfg.EnableAll || ciscoCfg.MessageCounter, + SequenceNumber: ciscoCfg.EnableAll || ciscoCfg.SequenceNumber, + CiscoHostname: ciscoCfg.EnableAll || ciscoCfg.Hostname, + SecondFractions: ciscoCfg.EnableAll || ciscoCfg.SecondFractions, } } From 14e6b2f51703b62e246f955bdcac959108deb5c3 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 03:33:04 -0500 Subject: [PATCH 09/20] fix: pass correct buffer --- .../syslog/internal/syslogtarget/syslogparser/syslogparser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go index 25e092b4f31..982df0b81cb 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser.go @@ -144,6 +144,6 @@ func ParseStream(cfg StreamParseConfig, r io.Reader, callback func(res *syslog.R return fmt.Errorf("invalid or unsupported framing. first byte: %q", b) } - parserFunc(opts...).Parse(r) + parserFunc(opts...).Parse(buf) return nil } From 0ab84ecad8823feee44b187fd52534748f2865ec Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 17:50:43 -0500 Subject: [PATCH 10/20] feat: parse cisco-specific fields --- .../internal/syslogtarget/syslogtarget.go | 9 +++ .../syslogtarget/syslogtarget_test.go | 74 +++++++++++++++---- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go index 537065c76f0..f322784573a 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net" + "strconv" "strings" "time" @@ -193,6 +194,14 @@ func (t *SyslogTarget) handleMessageRFC3164(connLabels labels.Labels, msg *rfc31 lb.Set("__syslog_message_msg_id", *v) } + // cisco-specific fields + if v := msg.MessageCounter; v != nil { + lb.Set("__syslog_message_msg_counter", strconv.Itoa(int(*v))) + } + if v := msg.Sequence; v != nil { + lb.Set("__syslog_message_sequence", strconv.Itoa(int(*v))) + } + processed, _ := relabel.Process(lb.Labels(), t.relabelConfig...) filtered := make(model.LabelSet) 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 136f2ee4a08..3b8fde70d85 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go @@ -12,7 +12,6 @@ import ( "iter" "net" "os" - "regexp" "slices" "sort" "testing" @@ -20,6 +19,8 @@ import ( "unicode/utf8" "github.com/go-kit/log" + "github.com/grafana/loki/pkg/push" + "github.com/grafana/regexp" "github.com/leodido/go-syslog/v4" promconfig "github.com/prometheus/common/config" "github.com/prometheus/common/model" @@ -27,9 +28,8 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" - "github.com/grafana/loki/pkg/push" - "github.com/grafana/alloy/internal/component/common/loki" + alloy_relabel "github.com/grafana/alloy/internal/component/common/relabel" scrapeconfig "github.com/grafana/alloy/internal/component/loki/source/syslog/config" "github.com/grafana/alloy/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser" ) @@ -463,9 +463,12 @@ func relabelConfig(t *testing.T) []*relabel.Config { - source_labels: ['__syslog_message_sd_custom_32473_exkey'] target_label: 'sd_custom_exkey' ` + return unmarshalRelabelCfg(t, relabelCfg) +} +func unmarshalRelabelCfg(t *testing.T, cfg string) []*relabel.Config { var relabels []*relabel.Config - err := yaml.Unmarshal([]byte(relabelCfg), &relabels) + err := yaml.Unmarshal([]byte(cfg), &relabels) require.NoError(t, err) // Set the validation scheme for all relabel configs @@ -605,18 +608,20 @@ func TestSyslogTarget_RFC3136CiscoComponents(t *testing.T) { logLine string expect loki.Entry ciscoComponents scrapeconfig.RFC3164CiscoComponents + relabelRules alloy_relabel.Rules }{ { - label: "all components", + label: "message with appname", logLine: "<189>643: *Jan 8 19:46:03.295: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback100, changed state to up", ciscoComponents: scrapeconfig.RFC3164CiscoComponents{ EnableAll: true, }, expect: loki.Entry{ Labels: model.LabelSet{ - "__syslog_message_severity": "notice", - "__syslog_message_facility": "local7", - "__syslog_message_app_name": "%LINEPROTO-5-UPDOWN", + "severity": "notice", + "facility": "local7", + "app_name": "%LINEPROTO-5-UPDOWN", + "msg_counter": "643", }, Entry: push.Entry{ Timestamp: parseDate(time.StampMilli, "Jan 8 19:46:03.295"), @@ -624,8 +629,52 @@ func TestSyslogTarget_RFC3136CiscoComponents(t *testing.T) { }, }, }, + { + label: "message with hostname", + logLine: "<189>269614: myhostname: Apr 11 10:02:08: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet7/0/34, changed state to up", + ciscoComponents: scrapeconfig.RFC3164CiscoComponents{ + Hostname: true, + SequenceNumber: true, + MessageCounter: true, + SecondFractions: false, + }, + expect: loki.Entry{ + Labels: model.LabelSet{ + "severity": "notice", + "facility": "local7", + "hostname": "myhostname", + "app_name": "%LINEPROTO-5-UPDOWN", + "msg_counter": "269614", + }, + Entry: push.Entry{ + Timestamp: parseDate(time.Stamp, "Apr 11 10:02:08"), + Line: "Line protocol on Interface GigabitEthernet7/0/34, changed state to up", + }, + }, + }, } + // config should be unmarshaled to autoinitialize regex, and defaults. + rawRelabelCfg := ` +- source_labels: ['__syslog_message_severity'] + target_label: 'severity' +- source_labels: ['__syslog_message_facility'] + target_label: 'facility' +- source_labels: ['__syslog_message_hostname'] + target_label: 'hostname' +- source_labels: ['__syslog_message_app_name'] + target_label: 'app_name' +- source_labels: ['__syslog_message_proc_id'] + target_label: 'proc_id' +- source_labels: ['__syslog_message_msg_id'] + target_label: 'msg_id' +- source_labels: ['__syslog_message_msg_counter'] + target_label: 'msg_counter' +- source_labels: ['__syslog_message_sequence'] + target_label: 'sequence' +` + + relabelCfg := unmarshalRelabelCfg(t, rawRelabelCfg) for _, tc := range cases { t.Run(tc.label, func(t *testing.T) { w := log.NewSyncWriter(os.Stderr) @@ -634,16 +683,14 @@ func TestSyslogTarget_RFC3136CiscoComponents(t *testing.T) { defer handler.Stop() metrics := NewMetrics(nil) - tgt, err := NewSyslogTarget(metrics, logger, handler, []*relabel.Config{}, &scrapeconfig.SyslogTargetConfig{ + tgt, err := NewSyslogTarget(metrics, logger, handler, relabelCfg, &scrapeconfig.SyslogTargetConfig{ ListenAddress: "127.0.0.1:0", ListenProtocol: "udp", LabelStructuredData: true, SyslogFormat: scrapeconfig.SyslogFormatRFC3164, RFC3164CiscoComponents: &tc.ciscoComponents, RFC3164DefaultToCurrentYear: true, - Labels: model.LabelSet{ - "test": "syslog_target", - }, + UseIncomingTimestamp: true, }) require.NoError(t, err) @@ -664,12 +711,11 @@ func TestSyslogTarget_RFC3136CiscoComponents(t *testing.T) { return len(handler.Received()) > 0 }, time.Second, 10*time.Millisecond, "handler didn't receive any message") - // TODO: cmp messages received := handler.Received() require.NotEmpty(t, received) msg := received[0] - t.Logf("%#v", msg) + require.Equal(t, tc.expect, msg) }) } } From 7c98766f7c51e26e0f71b579b6895c5824eaa159 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 18:04:55 -0500 Subject: [PATCH 11/20] feat: add cisco options to promtailconvert --- .../promtailconvert/internal/build/syslog.go | 10 ++++++++++ internal/loki/promtail/scrapeconfig/config.go | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/internal/converter/internal/promtailconvert/internal/build/syslog.go b/internal/converter/internal/promtailconvert/internal/build/syslog.go index 19a21ce143b..7d7d8475b42 100644 --- a/internal/converter/internal/promtailconvert/internal/build/syslog.go +++ b/internal/converter/internal/promtailconvert/internal/build/syslog.go @@ -46,6 +46,16 @@ func (s *ScrapeConfigBuilder) AppendSyslogConfig() { } } + if ciscoOpts := s.cfg.SyslogConfig.RFC3164CiscoComponents; ciscoOpts != nil { + listenerConfig.RFC3164CiscoComponents = &syslog.RFC3164CiscoComponents{ + EnableAll: ciscoOpts.EnableAll, + MessageCounter: ciscoOpts.MessageCounter, + SequenceNumber: ciscoOpts.SequenceNumber, + Hostname: ciscoOpts.Hostname, + SecondFractions: ciscoOpts.SecondFractions, + } + } + args := syslog.Arguments{ SyslogListeners: []syslog.ListenerConfig{ listenerConfig, diff --git a/internal/loki/promtail/scrapeconfig/config.go b/internal/loki/promtail/scrapeconfig/config.go index 8e5ff3fb902..9690400f5f6 100644 --- a/internal/loki/promtail/scrapeconfig/config.go +++ b/internal/loki/promtail/scrapeconfig/config.go @@ -170,7 +170,8 @@ type SyslogTargetConfig struct { TLSConfig promconfig.TLSConfig `yaml:"tls_config,omitempty"` - RawFormatOptions *SyslogRawFormatOptions `yaml:"raw_format_options"` + RawFormatOptions *SyslogRawFormatOptions `yaml:"raw_format_options"` + RFC3164CiscoComponents *SyslogRFC3164CiscoComponents `yaml:"rfc3164_cisco_components"` } type SyslogRawFormatOptions struct { @@ -181,6 +182,15 @@ func (config SyslogTargetConfig) IsRFC3164Message() bool { return config.SyslogFormat == SyslogFormatRFC3164 } +// SyslogRFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. +type SyslogRFC3164CiscoComponents struct { + EnableAll bool `yaml:"enable_all"` + MessageCounter bool `yaml:"message_counter"` + SequenceNumber bool `yaml:"sequence_number"` + Hostname bool `yaml:"hostname"` + SecondFractions bool `yaml:"second_fractions"` +} + // WindowsEventsTargetConfig describes a scrape config that listen for windows event logs. type WindowsEventsTargetConfig struct { // LCID (Locale ID) for event rendering From 85e7c83c44d030233984b9b7a28f132c09cb5600 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 18:09:06 -0500 Subject: [PATCH 12/20] feat: add cisco-specific fields to RFC5424 --- .../source/syslog/internal/syslogtarget/syslogtarget.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go index f322784573a..04d88c944ad 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget.go @@ -129,6 +129,14 @@ func (t *SyslogTarget) handleMessageRFC5424(connLabels labels.Labels, msg *rfc54 lb.Set("__syslog_message_msg_id", *v) } + // cisco-specific fields + if v := msg.MessageCounter; v != nil { + lb.Set("__syslog_message_msg_counter", strconv.Itoa(int(*v))) + } + if v := msg.Sequence; v != nil { + lb.Set("__syslog_message_sequence", strconv.Itoa(int(*v))) + } + if t.config.LabelStructuredData && msg.StructuredData != nil { for id, params := range *msg.StructuredData { id = strings.ReplaceAll(id, "@", "_") From 5ca1640e02c36d0b1c3036c41298ebcb14b52909 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 19:27:17 -0500 Subject: [PATCH 13/20] feat: update component docs --- .../components/loki/loki.source.syslog.md | 73 +++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index 78dc1883594..faafe631735 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -65,6 +65,8 @@ The `relabel_rules` field can make use of the `rules` export value from a [`loki * `__syslog_message_app_name` * `__syslog_message_proc_id` * `__syslog_message_msg_id` +* `__syslog_message_msg_counter` +* `__syslog_message_sequence` If there is [RFC5424](https://www.rfc-editor.org/rfc/rfc5424) compliant structured data in the parsed message, it will be applied to the log entry as a label with prefix `__syslog_message_sd_`. For example, if the structured data provided is `[example@99999 test="value"]`, the log entry will have the label `__syslog_message_sd_example_99999_test` with a value of `value`. @@ -88,11 +90,12 @@ loki.relabel "syslog" { You can use the following blocks with `loki.source.syslog`: -| Name | Description | Required | -|---------------------------------------------------------|-----------------------------------------------------------------------------|----------| -| [`listener`][listener] | Configures a listener for Syslog messages. | no | -| `listener` > [`raw_format_options`][raw_format_options] | Configures `raw` syslog format behavior. | no | -| `listener` > [`tls_config`][tls_config] | Configures TLS settings for connecting to the endpoint for TCP connections. | no | +| Name | Description | Required | +|-------------------------------------------------------------|-----------------------------------------------------------------------------|----------| +| [`listener`][listener] | Configures a listener for Syslog messages. | no | +| `listener` > [`raw_format_options`][raw_format_options] | Configures `raw` syslog format behavior. | no | +| `listener` > [`rfc3164_cisco_components`][cisco_components] | Configures parsing of non-standard Cisco IOS syslog extensions. | no | +| `listener` > [`tls_config`][tls_config] | Configures TLS settings for connecting to the endpoint for TCP connections. | no | The > symbol indicates deeper levels of nesting. For example, `listener` > `tls_config` refers to a `tls_config` block defined inside a `listener` block. @@ -100,6 +103,7 @@ For example, `listener` > `tls_config` refers to a `tls_config` block defined in [listener]: #listener [tls_config]: #tls_config [raw_format_options]: #raw_format_options +[cisco_components]: #rfc3164_cisco_components ### `listener` @@ -177,6 +181,65 @@ The following argument is supported: |---------------------------------|--------|-----------------------------------------------------------------------------|---------|----------| | `use_null_terminator_delimiter` | `bool` | Use null-terminator (`\0`) instead of line break (`\n`) to split log lines. | `false` | no | +### `rfc3164_cisco_components` + +{{< docs/shared lookup="stability/experimental_feature.md" source="alloy" version="" >}} + +The `rfc3164_cisco_components` configures parsing of non-standard Cisco IOS syslog extensions. + +{{< admonition type="note" >}} +This block can only be used when you set `syslog_format` to `rfc3164`. +{{< /admonition >}} + +The following argument is supported: + +| Name | Type | Description | Default | Required | +|--------------------|--------|-------------------------------------------------|---------|----------| +| `enable_all` | `bool` | Enables all components below. | `false` | no | +| `message_counter` | `bool` | Enables syslog message counter field parsing. | `false` | no | +| `sequence_number` | `bool` | Enables service sequence number field parsing. | `false` | no | +| `hostname` | `bool` | Enables origin hostname fleld parsing. | `false` | no | +| `second_fractions` | `bool` | Enables miliseconds parsing in timestamp field. | `false` | no | + +{{< admonition type="note" >}} +At-least one option has to be enabled if `enable_all` is set to `false`. +{{< /admonition >}} + +{{< admonition type="caution" >}} +The `rfc3164_cisco_components` configuration must match your Cisco device configuration. +The `loki.source.syslog` component cannot auto-detect which components are present because they share similar formats. +{{< /admonition >}} + +#### Cisco Device Configuration + +``` +conf t + +! Enable message counter (on by default for remote logging) +logging host 10.0.0.10 + +! Add service sequence numbers +service sequence-numbers + +! Add origin hostname +logging origin-id hostname + +! Enable millisecond timestamps +service timestamps log datetime msec localtime + +! Recommended: Enable NTP to remove asterisk +ntp server +``` + +#### Current Limitations + +* **Component Ordering**: When Cisco components are selectively disabled on the device but the parser expects them, parsing will fail or produce incorrect results. + Always match your parser configuration to your device configuration. +* **Structured Data**: Messages with RFC5424-style structured data blocks (from `logging host X session-id` or `sequence-num-session`) are not currently supported. + See the [upstream issue][go-syslog-issue] for details. + +[go-syslog-issue]: https://github.com/leodido/go-syslog/issues/35 + ### `tls_config` {{< docs/shared lookup="reference/components/tls-config-block.md" source="alloy" version="" >}} From f73da36e3697883daa77fe6f1534deba79b80c0c Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 19:42:42 -0500 Subject: [PATCH 14/20] fix: hide cisco ios support behind stability level --- .../component/loki/source/syslog/syslog.go | 5 ++ .../loki/source/syslog/syslog_test.go | 70 ++++++++++++++----- .../component/loki/source/syslog/types.go | 10 +-- 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/internal/component/loki/source/syslog/syslog.go b/internal/component/loki/source/syslog/syslog.go index cffeb14327b..e6f30eba3b4 100644 --- a/internal/component/loki/source/syslog/syslog.go +++ b/internal/component/loki/source/syslog/syslog.go @@ -2,6 +2,7 @@ package syslog import ( "context" + "errors" "fmt" "reflect" "sync" @@ -141,6 +142,10 @@ func (c *Component) checkExperimentalFeatures(args Arguments) error { if listener.SyslogFormat == scrapeconfig.SyslogFormatRaw { return fmt.Errorf("%q syslog format is available only at experimental stability level", scrapeconfig.SyslogFormatRaw) } + + if listener.RFC3164CiscoComponents != nil { + return errors.New("rfc3164_cisco_components block is available only at experimental stability level") + } } return nil diff --git a/internal/component/loki/source/syslog/syslog_test.go b/internal/component/loki/source/syslog/syslog_test.go index d54a55b4090..01265ea366e 100644 --- a/internal/component/loki/source/syslog/syslog_test.go +++ b/internal/component/loki/source/syslog/syslog_test.go @@ -282,24 +282,58 @@ func TestShutdownAndRebindOnSamePort(t *testing.T) { } } -func TestRawFormatRequiresExperimentalStabilityLevel(t *testing.T) { - opts := component.Options{ - Logger: util.TestAlloyLogger(t), - Registerer: prometheus.NewRegistry(), - OnStateChange: func(e component.Exports) {}, - MinStability: featuregate.StabilityGenerallyAvailable, +func TestExperimentalFeaturesStabilityLevel(t *testing.T) { + cases := []struct { + label string + expectErr string + setCfg func(*ListenerConfig) + }{ + { + label: "syslog-raw-format", + expectErr: "syslog format is available only at experimental stability level", + setCfg: func(lc *ListenerConfig) { + lc.SyslogFormat = scrapeconfig.SyslogFormatRaw + }, + }, + { + label: "cisco-ios", + expectErr: "rfc3164_cisco_components block is available only at experimental stability level", + setCfg: func(lc *ListenerConfig) { + lc.SyslogFormat = scrapeconfig.SyslogFormatRFC3164 + lc.RFC3164CiscoComponents = &RFC3164CiscoComponents{EnableAll: true} + }, + }, } - ch1 := loki.NewLogsReceiver() - args1 := Arguments{} - l1 := DefaultListenerConfig - l1.ListenAddress = "127.0.0.1:1234" - l1.ListenProtocol = syslogtarget.ProtocolTCP - l1.SyslogFormat = scrapeconfig.SyslogFormatRaw - args1.SyslogListeners = []ListenerConfig{l1} - args1.ForwardTo = []loki.LogsReceiver{ch1} - - _, err := New(opts, args1) - require.Error(t, err) - require.Error(t, err, "syslog format requires experimental stability level") + for _, tc := range cases { + t.Run(tc.label, func(t *testing.T) { + opts := component.Options{ + Logger: util.TestAlloyLogger(t), + Registerer: prometheus.NewRegistry(), + OnStateChange: func(e component.Exports) {}, + MinStability: featuregate.StabilityGenerallyAvailable, + } + + lc := DefaultListenerConfig + lc.ListenAddress = "127.0.0.1:1234" + lc.ListenProtocol = syslogtarget.ProtocolTCP + tc.setCfg(&lc) + + rcv := loki.NewLogsReceiver() + args := Arguments{ + SyslogListeners: []ListenerConfig{lc}, + ForwardTo: []loki.LogsReceiver{rcv}, + } + + // Check if requires experimental level + _, err := New(opts, args) + require.Error(t, err) + require.ErrorContains(t, err, tc.expectErr, "component should require experimental level") + + // Check if there is no error when stability level is experimental + opts.MinStability = featuregate.StabilityExperimental + _, err = New(opts, args) + require.NoError(t, err, "feature should work at experimental level") + }) + } } diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index af4be74434e..71a54fd45ab 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -142,11 +142,11 @@ func (sc ListenerConfig) Convert() (*scrapeconfig.SyslogTargetConfig, error) { if cmp := sc.RFC3164CiscoComponents; cmp != nil { cfg.RFC3164CiscoComponents = &scrapeconfig.RFC3164CiscoComponents{ - EnableAllComponents: cmp.EnableAll, - MessageCounter: cmp.MessageCounter, - SequenceNumber: cmp.SequenceNumber, - Hostname: cmp.Hostname, - SecondFractions: cmp.SecondFractions, + EnableAll: cmp.EnableAll, + MessageCounter: cmp.MessageCounter, + SequenceNumber: cmp.SequenceNumber, + Hostname: cmp.Hostname, + SecondFractions: cmp.SecondFractions, } } From 801763b6bdfcfb2e3b2ae349cc185ba255be0a62 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 19:57:57 -0500 Subject: [PATCH 15/20] fix: link anchor --- 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 faafe631735..1b62b3662ad 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -20,9 +20,9 @@ For a detailed example, refer to the [Monitor RFC5424-compliant syslog messages If your messages aren't RFC5424 compliant, you can use `raw` syslog format in combination with the [`loki.process`](./loki.process.md) component. Please note, that the `raw` syslog format is an [experimental][] feature. -{{< /admonition >}} [experimental]: https://grafana.com/docs/release-life-cycle/ +{{< /admonition >}} The component starts a new syslog listener for each of the given `config` blocks and fans out incoming entries to the list of receivers in `forward_to`. From e241107b0562ba5ebdb520f8c8fa9750c9e22d88 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:02:24 -0500 Subject: [PATCH 16/20] fix: admonition links --- .../sources/reference/components/loki/loki.source.syslog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index 1b62b3662ad..92d2bfb791d 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -154,16 +154,16 @@ The `rfc3164_default_to_current_year`, `use_incoming_timestamp` and `use_rfc5424 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. +[cef]: https://www.splunk.com/en_us/blog/learn/common-event-format-cef.html + {{< admonition type="note" >}} The `raw` format is an [experimental][] feature. Experimental features are subject to frequent breaking changes, and may be removed with no equivalent replacement. To enable and use an experimental feature, you must set the `stability.level` [flag][] to `experimental`. -{{< /admonition >}} [flag]: https://grafana.com/docs/alloy//reference/cli/run/ [experimental]: https://grafana.com/docs/release-life-cycle/ - -[cef]: https://www.splunk.com/en_us/blog/learn/common-event-format-cef.html +{{< /admonition >}} ### `raw_format_options` From 1c050cab95de97ba684515c29b6fdba4c2e23fa6 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:16:35 -0500 Subject: [PATCH 17/20] fix: CI test fails during new year start --- .../syslogtarget/syslogparser/syslogparser_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser_test.go b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser_test.go index 81c619a117f..d21e9802cd3 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser_test.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser/syslogparser_test.go @@ -6,18 +6,17 @@ import ( "testing" "time" - "github.com/grafana/alloy/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser" - "github.com/grafana/alloy/internal/util" "github.com/leodido/go-syslog/v4" "github.com/leodido/go-syslog/v4/rfc3164" "github.com/leodido/go-syslog/v4/rfc5424" "github.com/stretchr/testify/require" -) -var ( - defaultMaxMessageLength = 8192 + "github.com/grafana/alloy/internal/component/loki/source/syslog/internal/syslogtarget/syslogparser" + "github.com/grafana/alloy/internal/util" ) +var defaultMaxMessageLength = 8192 + func TestParseStream_OctetCounting(t *testing.T) { r := strings.NewReader("23 <13>1 - - - - - - First24 <13>1 - - - - - - Second") From 3cd3c3093dff0afc721a649cb0d3383e279822a0 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:30:02 -0500 Subject: [PATCH 18/20] fix: cisco component fields alloy tag --- internal/component/loki/source/syslog/types.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index 71a54fd45ab..b2d4a59fe8a 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -36,11 +36,11 @@ type RawFormatOptions struct { // RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. type RFC3164CiscoComponents struct { - EnableAll bool `alloy:"enable_all"` - MessageCounter bool `alloy:"message_counter"` - SequenceNumber bool `alloy:"sequence_number"` - Hostname bool `alloy:"hostname"` - SecondFractions bool `alloy:"second_fractions"` + EnableAll bool `alloy:"enable_all,optional"` + MessageCounter bool `alloy:"message_counter,optional"` + SequenceNumber bool `alloy:"sequence_number,optional"` + Hostname bool `alloy:"hostname,optional"` + SecondFractions bool `alloy:"second_fractions,optional"` } func (sc *RFC3164CiscoComponents) Validate() error { From b97bbef961d0bd65f5bd922e04f1a4bbb6251ef5 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:49:16 -0500 Subject: [PATCH 19/20] fix: cisco component fields alloy tag --- internal/component/loki/source/syslog/types.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index b2d4a59fe8a..d005579ea66 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -36,11 +36,11 @@ type RawFormatOptions struct { // RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. type RFC3164CiscoComponents struct { - EnableAll bool `alloy:"enable_all,optional"` - MessageCounter bool `alloy:"message_counter,optional"` - SequenceNumber bool `alloy:"sequence_number,optional"` - Hostname bool `alloy:"hostname,optional"` - SecondFractions bool `alloy:"second_fractions,optional"` + EnableAll bool `alloy:"enable_all,attr,optional"` + MessageCounter bool `alloy:"message_counter,attr,optional"` + SequenceNumber bool `alloy:"sequence_number,attr,optional"` + Hostname bool `alloy:"hostname,attr,optional"` + SecondFractions bool `alloy:"second_fractions,attr,optional"` } func (sc *RFC3164CiscoComponents) Validate() error { From 44636047ee9c03c026e1eb234495c1e30b86255f Mon Sep 17 00:00:00 2001 From: Denys Sedchenko <9203548+x1unix@users.noreply.github.com> Date: Sun, 4 Jan 2026 01:33:59 -0500 Subject: [PATCH 20/20] AI review Co-authored-by: Joe Harvey <51208233+jharvey10@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../reference/components/loki/loki.source.syslog.md | 8 ++++---- internal/component/loki/source/syslog/config/config.go | 2 +- .../syslog/internal/syslogtarget/syslogtarget_test.go | 2 +- internal/component/loki/source/syslog/types.go | 2 +- internal/loki/promtail/scrapeconfig/config.go | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/sources/reference/components/loki/loki.source.syslog.md b/docs/sources/reference/components/loki/loki.source.syslog.md index 92d2bfb791d..ca3e483777c 100644 --- a/docs/sources/reference/components/loki/loki.source.syslog.md +++ b/docs/sources/reference/components/loki/loki.source.syslog.md @@ -191,18 +191,18 @@ The `rfc3164_cisco_components` configures parsing of non-standard Cisco IOS sysl This block can only be used when you set `syslog_format` to `rfc3164`. {{< /admonition >}} -The following argument is supported: +The following arguments are supported: | Name | Type | Description | Default | Required | |--------------------|--------|-------------------------------------------------|---------|----------| | `enable_all` | `bool` | Enables all components below. | `false` | no | | `message_counter` | `bool` | Enables syslog message counter field parsing. | `false` | no | | `sequence_number` | `bool` | Enables service sequence number field parsing. | `false` | no | -| `hostname` | `bool` | Enables origin hostname fleld parsing. | `false` | no | -| `second_fractions` | `bool` | Enables miliseconds parsing in timestamp field. | `false` | no | +| `hostname` | `bool` | Enables origin hostname field parsing. | `false` | no | +| `second_fractions` | `bool` | Enables milliseconds parsing in timestamp field.| `false` | no | {{< admonition type="note" >}} -At-least one option has to be enabled if `enable_all` is set to `false`. +At least one option has to be enabled if `enable_all` is set to `false`. {{< /admonition >}} {{< admonition type="caution" >}} diff --git a/internal/component/loki/source/syslog/config/config.go b/internal/component/loki/source/syslog/config/config.go index 3d06263ef62..d0203c81dc3 100644 --- a/internal/component/loki/source/syslog/config/config.go +++ b/internal/component/loki/source/syslog/config/config.go @@ -55,7 +55,7 @@ func (s SyslogFormat) Validate() error { return fmt.Errorf("unknown syslog format: %q", s) } -// RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. +// RFC3164CiscoComponents enables Cisco IOS log line parsing and configures what fields to parse. type RFC3164CiscoComponents struct { EnableAll bool MessageCounter bool 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 3b8fde70d85..16df2cabb4b 100644 --- a/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go +++ b/internal/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go @@ -595,7 +595,7 @@ func parseCefLogLines(t *testing.T, lines iter.Seq[string]) []cefLogLine { return out } -func TestSyslogTarget_RFC3136CiscoComponents(t *testing.T) { +func TestSyslogTarget_RFC3164CiscoComponents(t *testing.T) { currentYear := time.Now().Year() parseDate := func(layout, value string) time.Time { r, err := time.Parse(layout, value) diff --git a/internal/component/loki/source/syslog/types.go b/internal/component/loki/source/syslog/types.go index d005579ea66..15d98311e0f 100644 --- a/internal/component/loki/source/syslog/types.go +++ b/internal/component/loki/source/syslog/types.go @@ -34,7 +34,7 @@ type RawFormatOptions struct { UseNullTerminatorDelimiter bool `alloy:"use_null_terminator_delimiter,attr,optional"` } -// RFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. +// RFC3164CiscoComponents enables Cisco IOS log line parsing and configures what fields to parse. type RFC3164CiscoComponents struct { EnableAll bool `alloy:"enable_all,attr,optional"` MessageCounter bool `alloy:"message_counter,attr,optional"` diff --git a/internal/loki/promtail/scrapeconfig/config.go b/internal/loki/promtail/scrapeconfig/config.go index 9690400f5f6..c316417116a 100644 --- a/internal/loki/promtail/scrapeconfig/config.go +++ b/internal/loki/promtail/scrapeconfig/config.go @@ -182,7 +182,7 @@ func (config SyslogTargetConfig) IsRFC3164Message() bool { return config.SyslogFormat == SyslogFormatRFC3164 } -// SyslogRFC3164CiscoComponents enables Cisco ios log line parsing and configures what fields to parse. +// SyslogRFC3164CiscoComponents enables Cisco IOS log line parsing and configures what fields to parse. type SyslogRFC3164CiscoComponents struct { EnableAll bool `yaml:"enable_all"` MessageCounter bool `yaml:"message_counter"`