Skip to content

Commit 6e4f88d

Browse files
authored
Merge pull request #106 from fluent-plugins-nursery/handle-CRI-O-log-on-partial_cri-mode
Handle CRI-O log on partial_cri mode
2 parents 321126d + 74d41b1 commit 6e4f88d

File tree

3 files changed

+82
-6
lines changed

3 files changed

+82
-6
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ Handle containerd/cri in Kubernetes.
196196
path /var/log/containers/*.log
197197
<parse>
198198
@type regexp
199-
expression /^(?<timestamp>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z) (?<output>\w+) (?<partial_flag>[FP]) (?<message>.+)$/
199+
expression /^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<message>.*)$/
200+
time_format %Y-%m-%dT%H:%M:%S.%L%z
200201
</parse>
201202
tag k8s
202203
@label @CONCAT
@@ -206,8 +207,9 @@ Handle containerd/cri in Kubernetes.
206207
<filter k8s>
207208
@type concat
208209
key message
209-
partial_key partial_flag
210-
partial_value P
210+
use_partial_cri_logtag true
211+
partial_cri_logtag_key logtag
212+
partial_cri_stream_key stream
211213
</filter>
212214
<match k8s>
213215
@type relabel

lib/fluent/plugin/filter_concat.rb

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ class ConcatFilter < Filter
3838
config_param :partial_metadata_format, :enum, list: [:"docker-fluentd", :"docker-journald", :"docker-journald-lowercase"], default: :"docker-fluentd"
3939
desc "If true, keep partial metadata"
4040
config_param :keep_partial_metadata, :bool, default: false
41+
desc "Use cri log tag to concatenate multiple records"
42+
config_param :use_partial_cri_logtag, :bool, default: false
43+
desc "The key name that is referred to concatenate records on cri log"
44+
config_param :partial_cri_logtag_key, :string, default: nil
45+
desc "The key name that is referred to detect stream name on cri log"
46+
config_param :partial_cri_stream_key, :string, default: "stream"
4147

4248
class TimeoutError < StandardError
4349
end
@@ -52,11 +58,18 @@ def initialize
5258
end
5359
end
5460

61+
def required_params
62+
params = [@n_lines.nil?, @multiline_start_regexp.nil?, @multiline_end_regexp.nil?, @partial_key.nil?, !@use_partial_metadata, !@use_partial_cri_logtag]
63+
names = ["n_lines", "multiline_start_regexp", "multiline_end_regexp", "partial_key", "use_partial_metadata", "use_partial_cri_logtag"]
64+
return params, names
65+
end
66+
5567
def configure(conf)
5668
super
5769

58-
if @n_lines.nil? && @multiline_start_regexp.nil? && @multiline_end_regexp.nil? && @partial_key.nil? && !@use_partial_metadata
59-
raise Fluent::ConfigError, "Either n_lines, multiline_start_regexp, multiline_end_regexp, partial_key or use_partial_metadata is required"
70+
params, names = required_params
71+
if params.all?
72+
raise Fluent::ConfigError, "Either #{[names[0..-2].join(", "), names[-1]].join(" or ")} is required"
6073
end
6174
if @n_lines && (@multiline_start_regexp || @multiline_end_regexp)
6275
raise Fluent::ConfigError, "n_lines and multiline_start_regexp/multiline_end_regexp are exclusive"
@@ -79,6 +92,15 @@ def configure(conf)
7992
if @use_partial_metadata && @partial_key
8093
raise Fluent::ConfigError, "use_partial_metadata and partial_key are exclusive"
8194
end
95+
if @use_partial_cri_logtag && @n_lines
96+
raise Fluent::ConfigError, "use_partial_cri_logtag and n_lines are exclusive"
97+
end
98+
if @use_partial_cri_logtag && (@multiline_start_regexp || @multiline_end_regexp)
99+
raise Fluent::ConfigError, "use_partial_cri_logtag and multiline_start_regexp/multiline_end_regexp are exclusive"
100+
end
101+
if @use_partial_cri_logtag && @partial_key
102+
raise Fluent::ConfigError, "use_partial_cri_logtag and partial_key are exclusive"
103+
end
82104

83105
@mode = nil
84106
case
@@ -110,6 +132,11 @@ def configure(conf)
110132
@partial_last_field = "container_partial_last".freeze
111133
@partial_message_indicator = @partial_id_field
112134
end
135+
when @use_partial_cri_logtag
136+
@mode = :partial_cri
137+
@partial_logtag_delimiter = ":".freeze
138+
@partial_logtag_continue = "P".freeze
139+
@partial_logtag_full = "F".freeze
113140
when @multiline_start_regexp || @multiline_end_regexp
114141
@mode = :regexp
115142
if @multiline_start_regexp
@@ -175,6 +202,9 @@ def filter_stream(tag, es)
175202
merged_record.delete(@partial_ordinal_field)
176203
merged_record.delete(@partial_last_field)
177204
end
205+
when :partial_cri
206+
merged_record.delete(@partial_cri_logtag_key) unless @keep_partial_key
207+
merged_record.delete(@partial_cri_stream_key)
178208
end
179209
new_es.add(time, merged_record)
180210
end
@@ -220,6 +250,8 @@ def process(tag, time, record)
220250
process_partial(stream_identity, tag, time, record)
221251
when :partial_metadata
222252
process_partial_metadata(stream_identity, tag, time, record)
253+
when :partial_cri
254+
process_partial_cri(stream_identity, tag, time, record)
223255
when :regexp
224256
process_regexp(stream_identity, tag, time, record)
225257
end
@@ -248,6 +280,18 @@ def process_partial(stream_identity, tag, time, record)
248280
new_es
249281
end
250282

283+
def process_partial_cri(stream_identity, tag, time, record)
284+
new_es = Fluent::MultiEventStream.new
285+
@buffer[stream_identity] << [tag, time, record]
286+
if record[@partial_cri_logtag_key].split(@partial_logtag_delimiter)[0] == @partial_logtag_full
287+
new_time, new_record = flush_buffer(stream_identity)
288+
time = new_time if @use_first_timestamp
289+
new_record.delete(@partial_cri_logtag_key)
290+
new_es.add(time, new_record)
291+
end
292+
new_es
293+
end
294+
251295
def process_partial_metadata(stream_identity, tag, time, record)
252296
new_es = Fluent::MultiEventStream.new
253297
@buffer[stream_identity] << [tag, time, record]

test/plugin/test_filter_concat.rb

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def filter_with_time(conf, messages, wait: nil)
5959
end
6060

6161
test "either" do
62-
assert_raise(Fluent::ConfigError.new("Either n_lines, multiline_start_regexp, multiline_end_regexp, partial_key or use_partial_metadata is required")) do
62+
assert_raise(Fluent::ConfigError.new("Either n_lines, multiline_start_regexp, multiline_end_regexp, partial_key, use_partial_metadata or use_partial_cri_logtag is required")) do
6363
create_driver(<<-CONFIG)
6464
key message
6565
CONFIG
@@ -125,6 +125,15 @@ def filter_with_time(conf, messages, wait: nil)
125125
CONFIG
126126
assert_equal(:regexp, d.instance.instance_variable_get(:@mode))
127127
end
128+
129+
test "use_partial_cri_logtag" do
130+
d = create_driver(<<-CONFIG)
131+
key message
132+
use_partial_cri_logtag true
133+
partial_cri_logtag_key logtag
134+
CONFIG
135+
assert_equal(:partial_cri, d.instance.instance_variable_get(:@mode))
136+
end
128137
end
129138

130139
sub_test_case "lines" do
@@ -1000,6 +1009,27 @@ def filter_with_time(conf, messages, wait: nil)
10001009
end
10011010
end
10021011

1012+
sub_test_case "CRI-O format log" do
1013+
test "filter with CRI-O style events" do
1014+
config = <<-CONFIG
1015+
key message
1016+
use_partial_cri_logtag true
1017+
partial_cri_logtag_key logtag
1018+
CONFIG
1019+
messages = [
1020+
{"stream" => "stdout", "logtag" => "F", "message" => "The content of the log entry 1"},
1021+
{"stream" => "stdout", "logtag" => "P", "message" => "First line of log entry 2"},
1022+
{"stream" => "stdout", "logtag" => "P", "message" => "Second line of the log entry 2"},
1023+
{"stream" => "stderr", "logtag" => "F", "message" => "Last line of the log entry 2"},
1024+
]
1025+
filtered = filter(config, messages, wait: 3)
1026+
expected = [
1027+
{"message" => "The content of the log entry 1"},
1028+
{"message" => "First line of log entry 2\nSecond line of the log entry 2\nLast line of the log entry 2"}]
1029+
assert_equal(expected, filtered)
1030+
end
1031+
end
1032+
10031033
sub_test_case "raise exception in on_timer" do
10041034
# See also https://github.com/fluent/fluentd/issues/1946
10051035
test "failed to flush timeout buffer" do

0 commit comments

Comments
 (0)