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 +4 -4
- data/.github/workflows/linux.yml +30 -0
- data/.github/workflows/windows.yml +26 -0
- data/.rubocop.yml +11 -8
- data/Appraisals +0 -3
- data/NEWS.md +36 -0
- data/README.md +132 -39
- data/fluent-plugin-concat.gemspec +3 -2
- data/lib/fluent/plugin/filter_concat.rb +205 -30
- metadata +26 -13
- data/.travis.yml +0 -21
- data/gemfiles/fluentd_v0.14.gemfile +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fa8ad39f08cb1de3cf3137fd5c504e285cc82107b10b3faf9455a8b08c002ca
|
4
|
+
data.tar.gz: d4f0fbfa8974961fcb2e4e7128e8d823c5a607a4087fc063d936c90896e267c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
40
|
+
Style/TrailingCommaInArrayLiteral:
|
33
41
|
Enabled: false
|
34
|
-
Style/
|
42
|
+
Style/TrailingCommaInHashLiteral:
|
35
43
|
Enabled: false
|
36
|
-
Style/
|
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
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
|
-
|
32
|
+
### Example
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
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.
|
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"
|
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
|
-
@
|
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
|
-
|
44
|
-
|
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 @
|
47
|
-
raise Fluent::ConfigError, "
|
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
|
-
|
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 @
|
116
|
-
|
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
|
-
|
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 &&
|
359
|
+
@multiline_start_regexp && @multiline_start_regexp.match?(text)
|
193
360
|
end
|
194
361
|
|
195
362
|
def lastline?(text)
|
196
|
-
@multiline_end_regexp &&
|
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
|
-
|
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 = @
|
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
|
-
@
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
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.
|
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:
|
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: '
|
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: '
|
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
|
-
|
143
|
-
|
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
|