fluent-plugin-record-demux 0.2.0 → 0.3.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: c9da92e93a04e15799949041055f91a9d9ff9327627028ce85322343778311bf
4
- data.tar.gz: 7eb377c975bdd3bcdbb192dd43a89af9995292dadc5bcfad3174f8f1f580ca09
3
+ metadata.gz: 04b8dcca3813f2024f2b47c2cde9dbbc131c3ac9d312cef5810189ce9d672228
4
+ data.tar.gz: 74485fe4f4d05eae9e13f55bf92a6eb9ea9648d309bbe697c69ee2aae0e59f3e
5
5
  SHA512:
6
- metadata.gz: a04985f89183aa35c8dbd0b4e72fbc430a5160a71b63eb539a25e720b11d51376f82cb87a07b6317fe89a001876a53161c78adda0151b6f51ca4b9536f826b7d
7
- data.tar.gz: 586b8c3ffc1b22d553a056fd0e3f96bf9ccada5e7d4c27a5e2b1e6ff714cc376d8c347f96278410b02dbc86c160d4abf94b05a4aa4abccc2f3da6ddb389d6181
6
+ metadata.gz: c499af008b748a39f9e85eae54ce319ef34c18d69876c4e3188c67d87a6eb513044e56fcb47a4aa3f4bc04f6bf63b83938c12f95f80d86c986ceb28d46e94b7c
7
+ data.tar.gz: 63639df945ee52df7e5443cd426aff84641889f6d258f5f49298b8cfd2841f6382642f2d66489ec08f9e49f9f9a8a4452fa098b449e25d46860bf3b7a56985e1
data/README.md CHANGED
@@ -76,6 +76,66 @@ into events:
76
76
  { "c": "data_c", "tags_1": "data_1", "tags_2": "data_2" }
77
77
  ```
78
78
 
79
+ ## plugin - out - record_dmux_picker
80
+
81
+ Demux record/event, by selecting nested fields for shared and demux parts.
82
+
83
+ It transforms 1 record/event to multiple record/event.
84
+
85
+ ### params
86
+
87
+ | setting | type | default | description |
88
+ |--------------------------------|-------------------------|---------|------------------------------------------------|
89
+ | tags | string | | tag to emit demux events on |
90
+ | demux_keys | hash | | nested key to demux |
91
+ | shared_keys | hash | {} | shared key to be present in each new event |
92
+ | demux_key_normalize | bool | false | format key to demux, in a key: , value: format |
93
+ | demux_key_normalize_key_name | string | key | when demux_key_normalize, key name to use |
94
+ | demux_key_normalize_value_name | string | value | when demux_key_normalize, value name to use |
95
+ | timestamp_key | string | nil | key for timestamp field (nil means skip) |
96
+ | timestamp_format | enum (iso, epochmillis) | iso | format of the time value |
97
+
98
+ ### example 1
99
+
100
+ Give this event :
101
+
102
+ ``` text
103
+ {
104
+ "label1": "value_label1",
105
+ "label2": "value_label2",
106
+ "label3": "value_label3",
107
+ "common": {
108
+ "metadata1": "value_metadata1",
109
+ "metadata2": "value_metadata2",
110
+ "metadata3": "value_metadata3",
111
+ "metadata4": "value_metadata4",
112
+ "metadata5": "value_metadata5",
113
+ "metadata6": "value_metadata6"
114
+ }
115
+ }
116
+
117
+ ```
118
+
119
+ With this conf :
120
+
121
+ ``` text
122
+ <match data>
123
+ @type record_demux_picker
124
+ tag demuxed
125
+ demux_keys $.label1:data1 , $.label2:data2 , $.label3:data3
126
+ shared_keys $.common.metadata1:description1 , $.common.metadata2:description2 , $.common.metadata3:description3
127
+ </match>
128
+ ```
129
+
130
+ It will produce :
131
+
132
+ ``` text
133
+ {"description1":"value_metadata1","description2":"value_metadata2","description3":"value_metadata3","data1":"value_label1"}
134
+ {"description1":"value_metadata1","description2":"value_metadata2","description3":"value_metadata3","data2":"value_label2"}
135
+ {"description1":"value_metadata1","description2":"value_metadata2","description3":"value_metadata3","data3":"value_label3"}
136
+
137
+ ```
138
+
79
139
  ## Installation
80
140
 
81
141
  Manual install, by executing:
data/Rakefile CHANGED
@@ -6,9 +6,15 @@ Bundler::GemHelper.install_tasks
6
6
  require 'rake/testtask'
7
7
  Rake::TestTask.new(:test) do |t|
8
8
  t.libs.push('lib', 'test')
9
- t.test_files = FileList['test/**/test_*.rb', 'test/**/*_test.rb',]
10
- t.verbose = true
11
- t.warning = true
9
+
10
+ t.test_files = if ENV['TEST_FILE']
11
+ FileList["#{ENV['TEST_FILE']}*",
12
+ "test/**/#{ENV['TEST_FILE']}*"]
13
+ else
14
+ FileList['test/**/test_*.rb', 'test/**/*_test.rb']
15
+ end
16
+ t.verbose = ENV.fetch('VERBOSE', false)
17
+ t.warning = ENV.fetch('WARNING', false)
12
18
  end
13
19
 
14
20
  require 'rubocop/rake_task'
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'fluent-plugin-record-demux'
8
- spec.version = '0.2.0'
8
+ spec.version = '0.3.0'
9
9
  spec.authors = ['Thomas Tych']
10
10
  spec.email = ['thomas.tych@gmail.com']
11
11
 
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency 'bump', '~> 0.10'
28
28
  spec.add_development_dependency 'bundler', '~> 2.6', '>= 2.6.5'
29
29
  spec.add_development_dependency 'byebug', '~> 11.1', '>= 11.1.3'
30
+ spec.add_development_dependency 'mocha', '~> 2.7', '>= 2.7.1'
30
31
  spec.add_development_dependency 'rake', '~> 13.2', '>= 13.2.1'
31
32
  spec.add_development_dependency 'reek', '~> 6.4'
32
33
  spec.add_development_dependency 'rubocop', '~> 1.74'
@@ -26,7 +26,7 @@ module Fluent
26
26
  helpers :event_emitter, :timer
27
27
 
28
28
  desc 'tag to emit events on'
29
- config_param :tag, :string, default: nil
29
+ config_param :tag, :string
30
30
 
31
31
  desc 'list of keys to demux'
32
32
  config_param :demux_keys, :array, value_type: :string, default: nil
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2024- Thomas Tych
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'fluent/plugin/output'
19
+
20
+ module Fluent
21
+ module Plugin
22
+ class RecordDemuxPickerOutput < Fluent::Plugin::Output
23
+ NAME = 'record_demux_picker'
24
+ Fluent::Plugin.register_output(NAME, self)
25
+
26
+ DEMUX_KEY_NORMALIZE_KEY_NAME = 'key'
27
+ DEMUX_KEY_NORMALIZE_VALUE_NAME = 'value'
28
+
29
+ helpers :event_emitter, :timer, :record_accessor
30
+
31
+ desc 'tag to emit events on'
32
+ config_param :tag, :string
33
+
34
+ desc 'list of keys to demux'
35
+ config_param :demux_keys, :hash
36
+ desc 'list of keys to be shared in all new events'
37
+ config_param :shared_keys, :hash, default: {}
38
+
39
+ desc 'normalize demux key format'
40
+ config_param :demux_key_normalize, :bool, default: false
41
+ desc 'demux key normalize key name'
42
+ config_param :demux_key_normalize_key_name, :string, default: DEMUX_KEY_NORMALIZE_KEY_NAME
43
+ desc 'demux key normalize value name'
44
+ config_param :demux_key_normalize_value_name, :string, default: DEMUX_KEY_NORMALIZE_VALUE_NAME
45
+
46
+ desc 'timestamp key'
47
+ config_param :timestamp_key, :string, default: nil
48
+ desc 'timestamp format'
49
+ config_param :timestamp_format, :enum, list: %i[iso epochmillis], default: :iso
50
+
51
+ def configure(conf)
52
+ super
53
+
54
+ @demux_keys_mappers = @demux_keys.map { |key, target| KeyMapper.new(key, target) }
55
+ @shared_keys_mappers = @shared_keys.map { |key, target| KeyMapper.new(key, target) }
56
+
57
+ true
58
+ end
59
+
60
+ def multi_workers_ready?
61
+ true
62
+ end
63
+
64
+ def process(_events_tag, events)
65
+ demux_events = MultiEventStream.new
66
+ events.each do |time, event|
67
+ new_events = process_event(time, event)
68
+ new_events.each { |new_event| demux_events.add(time, new_event) }
69
+ end
70
+ router.emit_stream(tag, demux_events)
71
+ end
72
+
73
+ def process_event(time, event)
74
+ shared_event = extract_shared_event(event)
75
+
76
+ @demux_keys_mappers.map do |mapper|
77
+ value = mapper.accessor.call(event)
78
+ shared_event
79
+ .merge(format_demux_key(mapper.target, value))
80
+ .merge(format_time(time))
81
+ rescue StandardError => e
82
+ log.warn "#{NAME} : failure while processing event : #{e}"
83
+ nil
84
+ end.compact
85
+ end
86
+
87
+ private
88
+
89
+ def extract_shared_event(event)
90
+ @shared_keys_mappers.each_with_object({}) do |mapper, new_event|
91
+ value = mapper.accessor.call(event)
92
+ new_event[mapper.target] = value
93
+ rescue StandardError => e
94
+ log.warn "#{NAME} : failure while processing event : #{e}"
95
+ next
96
+ end
97
+ end
98
+
99
+ def format_demux_key(key, value)
100
+ if demux_key_normalize
101
+ { demux_key_normalize_key_name => key,
102
+ demux_key_normalize_value_name => value }
103
+ else
104
+ { key => value }
105
+ end
106
+ end
107
+
108
+ def format_time(time)
109
+ return {} unless timestamp_key
110
+
111
+ { timestamp_key => format_timestamp(time) }
112
+ end
113
+
114
+ def format_timestamp(time)
115
+ return (time.to_time.utc.to_f * 1000).to_i if @timestamp_format == :epochmillis
116
+
117
+ time.to_time.utc.iso8601(3)
118
+ end
119
+
120
+ class KeyMapper
121
+ include Fluent::PluginHelper::RecordAccessor
122
+
123
+ attr_reader :key, :accessor, :target, :setter
124
+
125
+ def initialize(key, target)
126
+ @key = key
127
+ @accessor = record_accessor_create(key)
128
+ @target = target
129
+ @target ||= @accessor.keys.is_a?(Array) ? @accessor.keys.last : @accessor.keys
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-record-demux
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Tych
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-14 00:00:00.000000000 Z
10
+ date: 2025-04-07 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bump
@@ -63,6 +63,26 @@ dependencies:
63
63
  - - ">="
64
64
  - !ruby/object:Gem::Version
65
65
  version: 11.1.3
66
+ - !ruby/object:Gem::Dependency
67
+ name: mocha
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '2.7'
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 2.7.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.7'
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: 2.7.1
66
86
  - !ruby/object:Gem::Dependency
67
87
  name: rake
68
88
  requirement: !ruby/object:Gem::Requirement
@@ -219,6 +239,7 @@ files:
219
239
  - Rakefile
220
240
  - fluent-plugin-record-demux.gemspec
221
241
  - lib/fluent/plugin/out_record_demux.rb
242
+ - lib/fluent/plugin/out_record_demux_picker.rb
222
243
  homepage: https://gitlab.com/ttych/fluent-plugin-record-demux
223
244
  licenses:
224
245
  - Apache-2.0
@@ -238,7 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
238
259
  - !ruby/object:Gem::Version
239
260
  version: '0'
240
261
  requirements: []
241
- rubygems_version: 3.6.5
262
+ rubygems_version: 3.6.6
242
263
  specification_version: 4
243
264
  summary: fluentd plugin to demux record by keys.
244
265
  test_files: []