fluent-plugin-concat 2.2.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b9554bd1483439c3202f8372c5a0c1699446eb6880e386f938569c509705c86
4
- data.tar.gz: 717f110778d3f834a4c026816ddb9932b97968604ede88f1ab939b4293289b6f
3
+ metadata.gz: 0fa8ad39f08cb1de3cf3137fd5c504e285cc82107b10b3faf9455a8b08c002ca
4
+ data.tar.gz: d4f0fbfa8974961fcb2e4e7128e8d823c5a607a4087fc063d936c90896e267c9
5
5
  SHA512:
6
- metadata.gz: 5b84e5ebd5d8d071f3743194e80444dffbcd6737944e88a9d562d682127b7c243610dc10ea5b4c05d6cc9daed63e7cf5ffc439a7e24ea819f2565f642a783849
7
- data.tar.gz: d31210d2cfbe92f7d3489b46d5569524722e0124f247548264edb87694b0dd7d114d321db331e87288f2846e7e0b2baa99c11d9d20e2dbbec97bf9710233eeba
6
+ metadata.gz: 173c3b6dcb69212174c1bca085e44b26da8137c0c4cd935e622b54ba019150a720e1eb863a4c3aff7503b8ee752aa992e694e321423c0cc2e3d846ccf2d79215
7
+ data.tar.gz: 11f274a4e8e4ae32f8e8f91d4eabd7ba72d98c794ff202b5e111b475024b40cc61fae65698eaebf645cc161fa8b3a9c632ff1f6de778fa369afe9fa57459c126
@@ -0,0 +1,30 @@
1
+ name: Testing on Ubuntu
2
+ on:
3
+ - push
4
+ - pull_request
5
+ jobs:
6
+ build:
7
+ runs-on: ${{ matrix.os }}
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby:
12
+ - 2.5
13
+ - 2.6
14
+ - 2.7
15
+ - 3.0
16
+ os:
17
+ - ubuntu-latest
18
+ name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
19
+ steps:
20
+ - uses: actions/checkout@v2
21
+ - uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby }}
24
+ - name: unit testing
25
+ env:
26
+ CI: true
27
+ run: |
28
+ gem install bundler rake
29
+ bundle install --jobs 4 --retry 3
30
+ bundle exec rake test
@@ -0,0 +1,26 @@
1
+ name: Testing on Windows
2
+ on:
3
+ - push
4
+ - pull_request
5
+ jobs:
6
+ build:
7
+ runs-on: ${{ matrix.os }}
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby: [ '2.5', '2.6', '2.7', '3.0' ]
12
+ os:
13
+ - windows-latest
14
+ name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ - name: unit testing
21
+ env:
22
+ CI: true
23
+ run: |
24
+ gem install bundler rake
25
+ bundle install --jobs 4 --retry 3
26
+ bundle exec rake test
data/.rubocop.yml CHANGED
@@ -4,6 +4,11 @@ AllCops:
4
4
  Exclude:
5
5
  - "vendor/**/*"
6
6
 
7
+ Layout/MultilineMethodCallIndentation:
8
+ EnforcedStyle: indented
9
+ Layout/SpaceInsideBlockBraces:
10
+ EnforcedStyle: space
11
+ SpaceBeforeBlockParameters: false
7
12
  Lint/UnderscorePrefixedVariableName:
8
13
  Enabled: false
9
14
  Lint/UnusedMethodArgument:
@@ -19,6 +24,9 @@ Metrics/ParameterLists:
19
24
  Metrics/MethodLength:
20
25
  Max: 30
21
26
 
27
+ Naming/FileName:
28
+ Enabled: false
29
+
22
30
  Style/AsciiComments:
23
31
  Enabled: false
24
32
  Style/HashSyntax:
@@ -29,11 +37,11 @@ Style/FrozenStringLiteralComment:
29
37
  Enabled: false
30
38
  Style/StringLiterals:
31
39
  EnforcedStyle: double_quotes
32
- Style/TrailingCommaInLiteral:
40
+ Style/TrailingCommaInArrayLiteral:
33
41
  Enabled: false
34
- Style/TrailingCommaInArguments:
42
+ Style/TrailingCommaInHashLiteral:
35
43
  Enabled: false
36
- Style/FileName:
44
+ Style/TrailingCommaInArguments:
37
45
  Enabled: false
38
46
  Style/Documentation:
39
47
  Enabled: false
@@ -41,13 +49,8 @@ Style/WordArray:
41
49
  Enabled: false
42
50
  Style/BarePercentLiterals:
43
51
  EnforcedStyle: percent_q
44
- Style/SpaceInsideBlockBraces:
45
- EnforcedStyle: space
46
- SpaceBeforeBlockParameters: false
47
52
  Style/BracesAroundHashParameters:
48
53
  Enabled: false
49
- Style/MultilineMethodCallIndentation:
50
- EnforcedStyle: indented
51
54
  Style/DoubleNegation:
52
55
  Enabled: false
53
56
  Style/EmptyCaseCondition:
data/Appraisals CHANGED
@@ -1,3 +0,0 @@
1
- appraise "fluentd v0.14" do
2
- gem "fluentd", "~> 0.14.0"
3
- end
data/NEWS.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # ChangeLog
2
2
 
3
+ ## next
4
+
5
+ ### Improvements
6
+
7
+ * adds `partial_metadata_format` to support Docker 20.10 journald log driver improvements [moby/moby#41407](https://github.com/moby/moby/pull/41407)
8
+
9
+ ## v2.3.0
10
+
11
+ ### Improvements
12
+
13
+ * Support `partial_key`, `partial_value` to concatenate split log lines. See #46, #52
14
+
15
+ ## v2.2.3
16
+
17
+ ### Fixes
18
+
19
+ * Fix a bug that `@timeout_map` will be updated while traversing it. See #49
20
+
21
+ ## v.2.2.2
22
+
23
+ ### Fixes
24
+
25
+ * #48
26
+
27
+ ## v2.2.1
28
+
29
+ ### Fixes
30
+
31
+ * #45
32
+
33
+ ## v2.2.0
34
+
35
+ ### Fixes
36
+
37
+ * #43
38
+
3
39
  ## v2.0.0
4
40
 
5
41
  * Use Fluentd v0.14 API and drop Fluentd v0.12 or earlier support
data/README.md CHANGED
@@ -29,47 +29,56 @@ Or install it yourself as:
29
29
 
30
30
  ## Configuration
31
31
 
32
- **key** (required)
32
+ ### Example
33
33
 
34
- The key for part of multiline log.
35
-
36
- **separator**
37
-
38
- The separator of lines.
39
- Default value is `"\n"`.
40
-
41
- **n\_lines**
42
-
43
- The number of lines.
44
- This is exclusive with `multiline_start_regex`.
45
-
46
- **multiline\_start\_regexp**
47
-
48
- The regexp to match beginning of multiline.
49
- This is exclusive with `n_lines.`
50
-
51
- **multiline\_end\_regexp**
52
-
53
- The regexp to match ending of multiline.
54
- This is exclusive with `n_lines.`
55
-
56
- **continuous\_line\_regexp**
57
-
58
- The regexp to match continuous lines.
59
- This is exclusive with `n_lines.`
60
-
61
- **stream\_identity\_key**
62
-
63
- The key to determine which stream an event belongs to.
64
-
65
- **flush\_interval**
66
-
67
- The number of seconds after which the last received event log will be flushed.
68
- If specified 0, wait for next line forever.
69
-
70
- **use\_first\_timestamp**
34
+ ```
35
+ <filter docker.log>
36
+ @type concat
37
+ key loga
38
+ #separator "\n"
39
+ n_lines 10
40
+ #multiline_start_regexp /^Start/
41
+ #multiline_end_regexp /^End/
42
+ #continuous_line_regexp nil
43
+ #stream_identity_key nil
44
+ #flush_interval 60
45
+ #timeout_label nil
46
+ #use_first_timestamp false
47
+ #partial_key nil
48
+ #partial_value nil
49
+ #keep_partial_key false
50
+ #use_partial_metadata false
51
+ #keep_partial_metadata false
52
+ #partial\_metadata\_format docker-fluentd
53
+ #use\_partial\_cri\_logtag false
54
+ #partial\_cri\_logtag\_key nil
55
+ #partial\_cri\_stream\_key stream
56
+ </filter>
57
+ ```
71
58
 
72
- Use timestamp of first record when buffer is flushed.
59
+ ### Parameter
60
+
61
+ |parameter|description|default|
62
+ |---|---|---|
63
+ |key|The key for part of multiline log||
64
+ |separator|The separator of lines|`"\n"`|
65
+ |n\_lines|The number of lines. This is exclusive with `multiline_start_regex`|nil|
66
+ |multiline\_start\_regexp|The regexp to match beginning of multiline. This is exclusive with `n_lines`|nil|
67
+ |multiline\_end\_regexp|The regexp to match ending of multiline.This is exclusive with `n_lines`|nil|
68
+ |continuous\_line\_regexp|The regexp to match continuous lines.This is exclusive with `n_lines`|nil|
69
+ |stream\_identity\_key|The key to determine which stream an event belongs to|nil|
70
+ |flush\_interval|The number of seconds after which the last received event log will be flushed.If specified 0, wait for next line foreverr|60|
71
+ |timeout\_label|The label name to handle events caused by timeout|nil|
72
+ |use\_first\_timestamp|Use timestamp of first record when buffer is flushed|`false`|
73
+ |partial\_key|The field name that is the reference to concatenate records|nil|
74
+ |partial\_value|The value stored in the field specified by partial_key that represent partial log|nil|
75
+ |keep\_partial\_key|If true, keep partial_key in concatenated records|`false`|
76
+ |use\_partial\_metadata|Use partial metadata to concatenate multiple records|`false`|
77
+ |keep\_partial\_metadata|If true, keep partial metadata|`false`|
78
+ |partial\_metadata\_format|Input format of the partial metadata (fluentd or journald docker log driver) ( `docker-fluentd`, `docker-journald`, `docker-journald-lowercase`)<br>Configure based on the input plugin, that is used. <br>The docker fluentd and journald log drivers are behaving differently, so the plugin needs to know, what to look for.<br>Use `docker-journald-lowercase`, if you have `fields_lowercase true` in the `journald` source config |`docker-fluentd`|
79
+ |use\_partial\_cri\_logtag|bool (optional)|Use cri log tag to concatenate multiple records||
80
+ |partial\_cri\_logtag\_key|string (optional)|The key name that is referred to concatenate records on cri log||
81
+ |partial\_cri\_stream\_key|string (optional)|The key name that is referred to detect stream name on cri log|`stream`|
73
82
 
74
83
  ## Usage
75
84
 
@@ -137,6 +146,90 @@ Handle single line JSON from Docker containers.
137
146
  </filter>
138
147
  ```
139
148
 
149
+ Handle Docker logs splitted in several parts (using `partial_message`), and do not add new line between parts.
150
+
151
+ ```aconf
152
+ <filter>
153
+ @type concat
154
+ key log
155
+ partial_key partial_message
156
+ partial_value true
157
+ separator ""
158
+ </filter>
159
+ ```
160
+
161
+ (Docker v19.03+) Handle Docker logs splitted in several parts (using `use_partial_metadata`), and do not add new line between parts.
162
+
163
+ ```aconf
164
+ <filter>
165
+ @type concat
166
+ key log
167
+ use_partial_metadata true
168
+ separator ""
169
+ </filter>
170
+ ```
171
+
172
+ (Docker v20.10+) Handle Docker logs splitted in several parts (using `use_partial_metadata`), and do not add new line between parts.
173
+
174
+ Docker v20.10 improved partial message handling by adding better metadata in the journald log driver, this works now similarily to the fluentd log driver, but requires one additional setting
175
+
176
+ ```aconf
177
+ <filter>
178
+ @type concat
179
+ key log
180
+ use_partial_metadata true
181
+ partial_metadata_format docker-journald
182
+ separator ""
183
+ </filter>
184
+ ```
185
+
186
+ Handle Docker logs splitted in several parts (using newline detection), and do not add new line between parts (prior to Docker 18.06).
187
+
188
+ ```aconf
189
+ <filter **>
190
+ @type concat
191
+ key log
192
+ multiline_end_regexp /\\n$/
193
+ separator ""
194
+ </filter>
195
+ ```
196
+
197
+ Handle containerd/cri in Kubernetes.
198
+
199
+ ```aconf
200
+ <source>
201
+ @type tail
202
+ path /var/log/containers/*.log
203
+ <parse>
204
+ @type regexp
205
+ expression /^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<message>.*)$/
206
+ time_format %Y-%m-%dT%H:%M:%S.%L%z
207
+ </parse>
208
+ tag k8s
209
+ @label @CONCAT
210
+ </source>
211
+
212
+ <label @CONCAT>
213
+ <filter k8s>
214
+ @type concat
215
+ key message
216
+ use_partial_cri_logtag true
217
+ partial_cri_logtag_key logtag
218
+ partial_cri_stream_key stream
219
+ </filter>
220
+ <match k8s>
221
+ @type relabel
222
+ @label @OUTPUT
223
+ </match>
224
+ </label>
225
+
226
+ <label @OUTPUT>
227
+ <match>
228
+ @type stdout
229
+ </match>
230
+ </label>
231
+ ```
232
+
140
233
  ## Contributing
141
234
 
142
235
  1. Fork it
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "fluent-plugin-concat"
7
- spec.version = "2.2.1"
7
+ spec.version = "2.5.0"
8
8
  spec.authors = ["Kenji Okimoto"]
9
9
  spec.email = ["okimoto@clear-code.com"]
10
10
 
@@ -17,9 +17,10 @@ Gem::Specification.new do |spec|
17
17
  spec.require_paths = ["lib"]
18
18
 
19
19
  spec.add_runtime_dependency "fluentd", ">= 0.14.0", "< 2"
20
- spec.add_development_dependency "bundler", "~> 1.11"
20
+ spec.add_development_dependency "bundler"
21
21
  spec.add_development_dependency "rake", "~> 12.0"
22
22
  spec.add_development_dependency "test-unit", ">= 3.1.0"
23
23
  spec.add_development_dependency "test-unit-rr"
24
24
  spec.add_development_dependency "appraisal"
25
+ spec.add_development_dependency "webrick"
25
26
  end
@@ -26,6 +26,24 @@ module Fluent::Plugin
26
26
  config_param :timeout_label, :string, default: nil
27
27
  desc "Use timestamp of first record when buffer is flushed"
28
28
  config_param :use_first_timestamp, :bool, default: false
29
+ desc "The field name that is the reference to concatenate records"
30
+ config_param :partial_key, :string, default: nil
31
+ desc "The value stored in the field specified by partial_key that represent partial log"
32
+ config_param :partial_value, :string, default: nil
33
+ desc "If true, keep partial_key in concatenated records"
34
+ config_param :keep_partial_key, :bool, default: false
35
+ desc "Use partial metadata to concatenate multiple records"
36
+ config_param :use_partial_metadata, :bool, default: false
37
+ desc "Input format of the partial metadata (fluentd or journald docker log driver)"
38
+ config_param :partial_metadata_format, :enum, list: [:"docker-fluentd", :"docker-journald", :"docker-journald-lowercase"], default: :"docker-fluentd"
39
+ desc "If true, keep partial metadata"
40
+ 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"
29
47
 
30
48
  class TimeoutError < StandardError
31
49
  end
@@ -34,23 +52,91 @@ module Fluent::Plugin
34
52
  super
35
53
 
36
54
  @buffer = Hash.new {|h, k| h[k] = [] }
37
- @timeout_map = Hash.new {|h, k| h[k] = Fluent::Engine.now }
55
+ @timeout_map_mutex = Thread::Mutex.new
56
+ @timeout_map_mutex.synchronize do
57
+ @timeout_map = Hash.new {|h, k| h[k] = Fluent::Engine.now }
58
+ end
59
+ end
60
+
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
38
65
  end
39
66
 
40
67
  def configure(conf)
41
68
  super
42
69
 
43
- if @n_lines && (@multiline_start_regexp || @multiline_end_regexp || @continuous_line_regexp)
44
- raise Fluent::ConfigError, "n_lines and multiline_start_regexp/multiline_end_regexp/continuous_line_regexp are exclusive"
70
+ params, names = required_params
71
+ if params.all?
72
+ raise Fluent::ConfigError, "Either #{[names[0..-2].join(", "), names[-1]].join(" or ")} is required"
73
+ end
74
+ if @n_lines && (@multiline_start_regexp || @multiline_end_regexp)
75
+ raise Fluent::ConfigError, "n_lines and multiline_start_regexp/multiline_end_regexp are exclusive"
76
+ end
77
+ if @partial_key && @n_lines
78
+ raise Fluent::ConfigError, "partial_key and n_lines are exclusive"
79
+ end
80
+ if @partial_key && (@multiline_start_regexp || @multiline_end_regexp)
81
+ raise Fluent::ConfigError, "partial_key and multiline_start_regexp/multiline_end_regexp are exclusive"
82
+ end
83
+ if @partial_key && @partial_value.nil?
84
+ raise Fluent::ConfigError, "partial_value is required when partial_key is specified"
85
+ end
86
+ if @use_partial_metadata && @n_lines
87
+ raise Fluent::ConfigError, "use_partial_metadata and n_lines are exclusive"
45
88
  end
46
- if @n_lines.nil? && @multiline_start_regexp.nil? && @multiline_end_regexp.nil?
47
- raise Fluent::ConfigError, "Either n_lines or multiline_start_regexp or multiline_end_regexp is required"
89
+ if @use_partial_metadata && (@multiline_start_regexp || @multiline_end_regexp)
90
+ raise Fluent::ConfigError, "use_partial_metadata and multiline_start_regexp/multiline_end_regexp are exclusive"
91
+ end
92
+ if @use_partial_metadata && @partial_key
93
+ raise Fluent::ConfigError, "use_partial_metadata and partial_key are exclusive"
94
+ 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"
48
103
  end
49
104
 
50
105
  @mode = nil
51
106
  case
52
107
  when @n_lines
53
108
  @mode = :line
109
+ when @partial_key
110
+ @mode = :partial
111
+ when @use_partial_metadata
112
+ @mode = :partial_metadata
113
+ case @partial_metadata_format
114
+ when :"docker-fluentd"
115
+ @partial_message_field = "partial_message".freeze
116
+ @partial_id_field = "partial_id".freeze
117
+ @partial_ordinal_field = "partial_ordinal".freeze
118
+ @partial_last_field = "partial_last".freeze
119
+ @partial_message_indicator = @partial_message_field
120
+ when :"docker-journald"
121
+ @partial_message_field = "CONTAINER_PARTIAL_MESSAGE".freeze
122
+ @partial_id_field = "CONTAINER_PARTIAL_ID".freeze
123
+ @partial_ordinal_field = "CONTAINER_PARTIAL_ORDINAL".freeze
124
+ @partial_last_field = "CONTAINER_PARTIAL_LAST".freeze
125
+ # the journald log driver does not add CONTAINER_PARTIAL_MESSAGE to the last message
126
+ # so we help ourself by using another indicator
127
+ @partial_message_indicator = @partial_id_field
128
+ when :"docker-journald-lowercase"
129
+ @partial_message_field = "container_partial_message".freeze
130
+ @partial_id_field = "container_partial_id".freeze
131
+ @partial_ordinal_field = "container_partial_ordinal".freeze
132
+ @partial_last_field = "container_partial_last".freeze
133
+ @partial_message_indicator = @partial_id_field
134
+ 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
54
140
  when @multiline_start_regexp || @multiline_end_regexp
55
141
  @mode = :regexp
56
142
  if @multiline_start_regexp
@@ -78,22 +164,49 @@ module Fluent::Plugin
78
164
  end
79
165
 
80
166
  def filter_stream(tag, es)
167
+ if /\Afluent\.(?:trace|debug|info|warn|error|fatal)\z/ =~ tag
168
+ return es
169
+ end
170
+
81
171
  new_es = Fluent::MultiEventStream.new
82
172
  es.each do |time, record|
83
- if /\Afluent\.(?:trace|debug|info|warn|error|fatal)\z/ =~ tag
84
- new_es.add(time, record)
85
- next
86
- end
87
173
  unless record.key?(@key)
88
174
  new_es.add(time, record)
89
175
  next
90
176
  end
177
+ if @mode == :partial
178
+ unless record.key?(@partial_key)
179
+ new_es.add(time, record)
180
+ next
181
+ end
182
+ end
183
+ if @mode == :partial_metadata
184
+ unless record.key?(@partial_message_indicator)
185
+ new_es.add(time, record)
186
+ next
187
+ end
188
+ end
91
189
  begin
92
190
  flushed_es = process(tag, time, record)
93
191
  unless flushed_es.empty?
94
192
  flushed_es.each do |_time, new_record|
95
193
  time = _time if @use_first_timestamp
96
- new_es.add(time, record.merge(new_record))
194
+ merged_record = record.merge(new_record)
195
+ case @mode
196
+ when :partial
197
+ merged_record.delete(@partial_key) unless @keep_partial_key
198
+ when :partial_metadata
199
+ unless @keep_partial_metadata
200
+ merged_record.delete(@partial_message_field)
201
+ merged_record.delete(@partial_id_field)
202
+ merged_record.delete(@partial_ordinal_field)
203
+ merged_record.delete(@partial_last_field)
204
+ 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)
208
+ end
209
+ new_es.add(time, merged_record)
97
210
  end
98
211
  end
99
212
  rescue => e
@@ -109,18 +222,36 @@ module Fluent::Plugin
109
222
  return if @flush_interval <= 0
110
223
  return if @finished
111
224
  flush_timeout_buffer
225
+ rescue => e
226
+ log.error "failed to flush timeout buffer", error: e
112
227
  end
113
228
 
114
229
  def process(tag, time, record)
115
- if @stream_identity_key
116
- stream_identity = "#{tag}:#{record[@stream_identity_key]}"
230
+ if @mode == :partial_metadata
231
+ if @stream_identity_key
232
+ stream_identity = %Q(#{tag}:#{record[@stream_identity_key]}#{record[@partial_id_field]})
233
+ else
234
+ stream_identity = %Q(#{tag}:#{record[@partial_id_field]})
235
+ end
117
236
  else
118
- stream_identity = "#{tag}:default"
237
+ if @stream_identity_key
238
+ stream_identity = "#{tag}:#{record[@stream_identity_key]}"
239
+ else
240
+ stream_identity = "#{tag}:default"
241
+ end
242
+ end
243
+ @timeout_map_mutex.synchronize do
244
+ @timeout_map[stream_identity] = Fluent::Engine.now
119
245
  end
120
- @timeout_map[stream_identity] = Fluent::Engine.now
121
246
  case @mode
122
247
  when :line
123
248
  process_line(stream_identity, tag, time, record)
249
+ when :partial
250
+ process_partial(stream_identity, tag, time, record)
251
+ when :partial_metadata
252
+ process_partial_metadata(stream_identity, tag, time, record)
253
+ when :partial_cri
254
+ process_partial_cri(stream_identity, tag, time, record)
124
255
  when :regexp
125
256
  process_regexp(stream_identity, tag, time, record)
126
257
  end
@@ -137,6 +268,42 @@ module Fluent::Plugin
137
268
  new_es
138
269
  end
139
270
 
271
+ def process_partial(stream_identity, tag, time, record)
272
+ new_es = Fluent::MultiEventStream.new
273
+ @buffer[stream_identity] << [tag, time, record]
274
+ unless @partial_value == record[@partial_key]
275
+ new_time, new_record = flush_buffer(stream_identity)
276
+ time = new_time if @use_first_timestamp
277
+ new_record.delete(@partial_key)
278
+ new_es.add(time, new_record)
279
+ end
280
+ new_es
281
+ end
282
+
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
+
295
+ def process_partial_metadata(stream_identity, tag, time, record)
296
+ new_es = Fluent::MultiEventStream.new
297
+ @buffer[stream_identity] << [tag, time, record]
298
+ if record[@partial_last_field] == "true"
299
+ new_time, new_record = flush_buffer(stream_identity)
300
+ time = new_time if @use_first_timestamp
301
+ new_record.delete(@partial_key)
302
+ new_es.add(time, new_record)
303
+ end
304
+ new_es
305
+ end
306
+
140
307
  def process_regexp(stream_identity, tag, time, record)
141
308
  new_es = Fluent::MultiEventStream.new
142
309
  case
@@ -189,23 +356,29 @@ module Fluent::Plugin
189
356
  end
190
357
 
191
358
  def firstline?(text)
192
- @multiline_start_regexp && !!@multiline_start_regexp.match(text)
359
+ @multiline_start_regexp && @multiline_start_regexp.match?(text)
193
360
  end
194
361
 
195
362
  def lastline?(text)
196
- @multiline_end_regexp && !!@multiline_end_regexp.match(text)
363
+ @multiline_end_regexp && @multiline_end_regexp.match?(text)
197
364
  end
198
365
 
199
366
  def continuous_line?(text)
200
367
  if @continuous_line_regexp
201
- !!@continuous_line_regexp.match(text)
368
+ @continuous_line_regexp.match?(text)
202
369
  else
203
370
  true
204
371
  end
205
372
  end
206
373
 
207
374
  def flush_buffer(stream_identity, new_element = nil)
208
- lines = @buffer[stream_identity].map {|_tag, _time, record| record[@key] }
375
+ lines = if @mode == :partial_metadata
376
+ @buffer[stream_identity]
377
+ .sort_by {|_tag, _time, record| record[@partial_ordinal_field].to_i }
378
+ .map {|_tag, _time, record| record[@key] }
379
+ else
380
+ @buffer[stream_identity].map {|_tag, _time, record| record[@key] }
381
+ end
209
382
  _tag, time, first_record = @buffer[stream_identity].first
210
383
  new_record = {
211
384
  @key => lines.join(@separator)
@@ -218,18 +391,20 @@ module Fluent::Plugin
218
391
  def flush_timeout_buffer
219
392
  now = Fluent::Engine.now
220
393
  timeout_stream_identities = []
221
- @timeout_map.each do |stream_identity, previous_timestamp|
222
- next if @flush_interval > (now - previous_timestamp)
223
- next if @buffer[stream_identity].empty?
224
- time, flushed_record = flush_buffer(stream_identity)
225
- timeout_stream_identities << stream_identity
226
- tag = stream_identity.split(":").first
227
- message = "Timeout flush: #{stream_identity}"
228
- handle_timeout_error(tag, @use_first_timestamp ? time : now, flushed_record, message)
229
- log.info(message)
230
- end
231
- @timeout_map.reject! do |stream_identity, _|
232
- timeout_stream_identities.include?(stream_identity)
394
+ @timeout_map_mutex.synchronize do
395
+ @timeout_map.each do |stream_identity, previous_timestamp|
396
+ next if @flush_interval > (now - previous_timestamp)
397
+ next if @buffer[stream_identity].empty?
398
+ time, flushed_record = flush_buffer(stream_identity)
399
+ timeout_stream_identities << stream_identity
400
+ tag = stream_identity.split(":").first
401
+ message = "Timeout flush: #{stream_identity}"
402
+ handle_timeout_error(tag, @use_first_timestamp ? time : now, flushed_record, message)
403
+ log.info(message)
404
+ end
405
+ @timeout_map.reject! do |stream_identity, _|
406
+ timeout_stream_identities.include?(stream_identity)
407
+ end
233
408
  end
234
409
  end
235
410
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-concat
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenji Okimoto
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-03 00:00:00.000000000 Z
11
+ date: 2021-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -34,16 +34,16 @@ dependencies:
34
34
  name: bundler
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '1.11'
39
+ version: '0'
40
40
  type: :development
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
44
+ - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '1.11'
46
+ version: '0'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -100,6 +100,20 @@ dependencies:
100
100
  - - ">="
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: webrick
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
103
117
  description: Fluentd Filter plugin to concat multiple event messages
104
118
  email:
105
119
  - okimoto@clear-code.com
@@ -108,9 +122,10 @@ extensions: []
108
122
  extra_rdoc_files: []
109
123
  files:
110
124
  - ".github/ISSUE_TEMPLATE.md"
125
+ - ".github/workflows/linux.yml"
126
+ - ".github/workflows/windows.yml"
111
127
  - ".gitignore"
112
128
  - ".rubocop.yml"
113
- - ".travis.yml"
114
129
  - Appraisals
115
130
  - Gemfile
116
131
  - LICENSE.txt
@@ -118,13 +133,12 @@ files:
118
133
  - README.md
119
134
  - Rakefile
120
135
  - fluent-plugin-concat.gemspec
121
- - gemfiles/fluentd_v0.14.gemfile
122
136
  - lib/fluent/plugin/filter_concat.rb
123
137
  homepage: https://github.com/fluent-plugins-nursery/fluent-plugin-concat
124
138
  licenses:
125
139
  - MIT
126
140
  metadata: {}
127
- post_install_message:
141
+ post_install_message:
128
142
  rdoc_options: []
129
143
  require_paths:
130
144
  - lib
@@ -139,9 +153,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
153
  - !ruby/object:Gem::Version
140
154
  version: '0'
141
155
  requirements: []
142
- rubyforge_project:
143
- rubygems_version: 2.7.3
144
- signing_key:
156
+ rubygems_version: 3.2.3
157
+ signing_key:
145
158
  specification_version: 4
146
159
  summary: Fluentd Filter plugin to concat multiple event messages
147
160
  test_files: []
data/.travis.yml DELETED
@@ -1,21 +0,0 @@
1
- sudo: false
2
- language: ruby
3
-
4
- notifications:
5
- webhooks:
6
- urls:
7
- secure: NhOBulc3nFAnJrCr9G0/3IGd1pOb/Zk0Wyk9Jqrf7PHnI4mZOIgttGnewZx1sG96NWrs0Braue5vXwFBTrJ60J6EW3+Q33XzhaZR+Q95jEb+5vcdIP69TYs0TgOIiOouo69Y4rIE1ANYuF/1cBfCKxGulpOIKUCW5LYPkyUEwQy+7VccULctCYCha2OYHQau5SUITCQQqZMfYCvZ+9FRubhR+OiiAnwduuzixKm5b2sa2K4lCKy2vsz3JZtjvQ6/7WM5JsipErtuUY2fDlrWSr/9SehRu8LCD119FjV/HcaAffFMokX+8vJm6RLGcyx/0mAejEqaBofqf9vi1KQJKsKuEe8N9IUpoLrl36RYVfDDRNDqm0pSkrz/KaNxSSe5sDNsCFY+uEFhtiPMHJiSlyEA+BVqnUeoM9pSWp3pcTsIHAjq5VGfQ6u9IooUODCASBlOsLuPu+FYEWG3dC3oiOLEIqQ+WywJg2P7I4dJNhyivti5j61czipTGj28ReFiydp5macKabkvAFBvOW8q07QBO4cvjixhr8hiUgMEVdo5y5dqNhLvS182by3OpmtaSQfpuI8QXytiN9629lWzB7qu0Q7Pji/5wSqEuCdaEHjF5uCVYLFE2LaGJdlTLBg9n0vFfFpJXnP1q0nehq2qRs30pNcgkcCKfEIPJgFgCac=
8
- on_success: change
9
- on_failure: always
10
- on_start: never
11
-
12
- rvm:
13
- - 2.1
14
- - 2.2
15
- - 2.3
16
- - 2.4.3
17
- - 2.5.0
18
-
19
- gemfile:
20
- - Gemfile
21
- - gemfiles/fluentd_v0.14.gemfile
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "fluentd", "~> 0.14.0"
6
-
7
- gemspec :path => "../"