diff --git a/lib/fluent/plugin/in_syslog.rb b/lib/fluent/plugin/in_syslog.rb index 704b801932..665aeff0f5 100644 --- a/lib/fluent/plugin/in_syslog.rb +++ b/lib/fluent/plugin/in_syslog.rb @@ -27,7 +27,7 @@ class SyslogInput < Input helpers :parser, :compat_parameters, :server DEFAULT_PARSER = 'syslog' - SYSLOG_REGEXP = /^\<([0-9]+)\>(.*)/ + SYSLOG_REGEXP = /\A\<([0-9]+)\>(.*)/ FACILITY_MAP = { 0 => 'kern', diff --git a/lib/fluent/plugin/parser_syslog.rb b/lib/fluent/plugin/parser_syslog.rb index 0fefb2e2f1..52c3b1f066 100644 --- a/lib/fluent/plugin/parser_syslog.rb +++ b/lib/fluent/plugin/parser_syslog.rb @@ -38,15 +38,15 @@ class SyslogParser < Parser \A<(?[0-9]{1,3})\>[1-9]\d{0,2} %s\z EOS - REGEXP_DETECT_RFC5424 = /^\<[0-9]{1,3}\>[1-9]\d{0,2}/ + REGEXP_DETECT_RFC5424 = /\A\<[0-9]{1,3}\>[1-9]\d{0,2}/ RFC3164_WITHOUT_TIME_AND_PRI_REGEXP = /(?[^ ]*) (?[^ :\[]*)(?:\[(?[0-9]+)\])?(?:[^\:]*\:)? *(?.*)$/ RFC3164_CAPTURES = RFC3164_WITHOUT_TIME_AND_PRI_REGEXP.names.freeze - RFC3164_PRI_REGEXP = /^<(?[0-9]{1,3})>/ + RFC3164_PRI_REGEXP = /\A<(?[0-9]{1,3})>/ RFC5424_WITHOUT_TIME_AND_PRI_REGEXP = /(?[!-~]{1,255}) (?[!-~]{1,48}) (?[!-~]{1,128}) (?[!-~]{1,32}) (?(?:\-|(?:\[.*?(?.+))?\z/m RFC5424_CAPTURES = RFC5424_WITHOUT_TIME_AND_PRI_REGEXP.names.freeze - RFC5424_PRI_REGEXP = /^<(?\d{1,3})>\d\d{0,2}\s/ + RFC5424_PRI_REGEXP = /\A<(?\d{1,3})>\d\d{0,2}\s/ config_set_default :time_format, "%b %d %H:%M:%S" desc 'If the incoming logs have priority prefix, e.g. <9>, set true' diff --git a/test/plugin/test_in_syslog.rb b/test/plugin/test_in_syslog.rb index bc52eecdc2..df8e0c9661 100755 --- a/test/plugin/test_in_syslog.rb +++ b/test/plugin/test_in_syslog.rb @@ -197,6 +197,27 @@ def test_space_after_input_owned_priority_preserves_input_priority_syntax(parser assert_equal(messages[2], d.events[2][2]['unmatched_line']) end + def test_priority_on_a_later_line_is_unmatched_when_input_parses_priority + d = create_driver([ + ipv4_config, + 'emit_unmatched_lines true', + '', + ' @type none', + '', + ].join("\n")) + + message = "first line\n<14>second line" + d.run(expect_emits: 1) do + u = UDPSocket.new + u.connect('127.0.0.1', @port) + u.send(message, 0) + end + + assert_equal(1, d.events.size) + assert_equal('syslog.unmatched', d.events[0][0]) + assert_equal(message, d.events[0][2]['unmatched_line']) + end + def test_msg_size d = create_driver tests = create_test_case diff --git a/test/plugin/test_parser_syslog.rb b/test/plugin/test_parser_syslog.rb index 9d55c4f7d4..a96dd360ed 100644 --- a/test/plugin/test_parser_syslog.rb +++ b/test/plugin/test_parser_syslog.rb @@ -318,6 +318,42 @@ def test_truncated_priority_or_timestamp_is_rejected_without_raising(data) assert_input_rejected(text, :rejects) end + data( + 'regexp/rfc5424' => ['regexp', 'rfc5424', "first line\n<14>1 2026-04-25T16:43:29Z host app 123 ID - second line"], + 'string/rfc5424' => ['string', 'rfc5424', "first line\n<14>1 2026-04-25T16:43:29Z host app 123 ID - second line"], + 'regexp/rfc3164' => ['regexp', 'rfc3164', "first line\n<14>Apr 25 16:43:29 host app: second line"], + 'string/rfc3164' => ['string', 'rfc3164', "first line\n<14>Apr 25 16:43:29 host app: second line"], + 'regexp/auto' => ['regexp', 'auto', "first line\n<14>1 2026-04-25T16:43:29Z host app 123 ID - second line"], + 'string/auto' => ['string', 'auto', "first line\n<14>1 2026-04-25T16:43:29Z host app 123 ID - second line"], + ) + def test_priority_on_a_later_line_is_rejected(data) + parser_engine, message_format, text = data + @parser.configure( + 'parser_engine' => parser_engine, + 'message_format' => message_format, + 'with_priority' => true, + ) + + assert_input_rejected(text, :rejects) + end + + data('regexp' => 'regexp', 'string' => 'string') + def test_auto_detects_rfc3164_when_a_later_line_looks_like_rfc5424(parser_engine) + @parser.configure( + 'parser_engine' => parser_engine, + 'message_format' => 'auto', + 'with_priority' => true, + ) + + text = "<13>Apr 25 16:43:29 web01 nginx: request failed:\n<14>1 2026-04-25T16:43:29Z host app 123 ID - second line" + time = record = nil + @parser.instance.parse(text) do |t, r| + time, record = t, r + end + assert_equal(event_time('Apr 25 16:43:29', format: '%b %d %H:%M:%S'), time) + assert_equal([13, 'web01', 'nginx'], record.values_at('pri', 'host', 'ident')) + end + data( 'rfc5424' => ['rfc5424', 'time_format'], 'auto' => ['auto', 'rfc5424_time_format'],