fluent-plugin-remove-empty 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c27b47de51f0e72ef214b0d5c1951bd9922168d5
4
+ data.tar.gz: 2601881938c556aa5b6478ab1363afb12d1abfa8
5
+ SHA512:
6
+ metadata.gz: 1dc1429b3686c5f6c498f202a57dc9b09fc15f443880b0623602aac247e0eee5ee3dddccbd2976dddc2b3db79a38415fb73dc494ca348e465d9207a2e825afb7
7
+ data.tar.gz: ef9cb7638d5c22438bae04da151efc50183d438357b10417ca7ee2de77ee981eae879ad1c96dd01fd4958a2a872fe4f5e99ddfc14f30a90b757cabda1bee0380
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,9 @@
1
+ # fluent-plugin-remove-empty
2
+
3
+ Fluentd plugin to remove empty fields of a event record
4
+
5
+ ## Installation
6
+
7
+ Use RubyGems:
8
+
9
+ gem install fluent-plugin-remove-empty
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "fluent-plugin-remove-empty"
6
+ gem.version = "0.0.1"
7
+ gem.authors = ["Chadin Anuwattanaporn"]
8
+ gem.email = "chadin@sogamo.com"
9
+ gem.homepage = "https://github.com/newcmd001/fluent-plugin-remove-empty"
10
+ gem.description = "Fluentd plugin to remove empty fields of a event record"
11
+ gem.summary = gem.description
12
+ gem.licenses = ["MIT"]
13
+ gem.has_rdoc = false
14
+
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ gem.require_paths = ['lib']
19
+
20
+ gem.add_dependency "fluentd", "~> 0.10.17"
21
+ gem.add_development_dependency "rake"
22
+ gem.add_development_dependency "rspec"
23
+ gem.add_development_dependency "pry"
24
+ gem.add_development_dependency "pry-nav"
25
+ end
@@ -0,0 +1,176 @@
1
+ require 'socket'
2
+ require 'ostruct'
3
+
4
+ module Fluent
5
+ class RemoveEmptyOutput < Output
6
+ Fluent::Plugin.register_output('remove_empty', self)
7
+
8
+ def initialize
9
+ super
10
+ end
11
+
12
+ config_param :tag, :string, :default => nil
13
+
14
+ BUILTIN_CONFIGURATIONS = %W(type tag)
15
+
16
+ # To support log_level option implemented by Fluentd v0.10.43
17
+ unless method_defined?(:log)
18
+ define_method("log") { $log }
19
+ end
20
+
21
+ def configure(conf)
22
+ super
23
+
24
+ @map = {}
25
+ conf.each_pair { |k, v|
26
+ next if BUILTIN_CONFIGURATIONS.include?(k)
27
+ conf.has_key?(k) # to suppress unread configuration warning
28
+ @map[k] = v
29
+ }
30
+
31
+ if @tag.nil?
32
+ raise Fluent::ConfigError, "out_remove_empty: `tag` must be specified"
33
+ end
34
+
35
+ @placeholder_expander =
36
+ if @enable_ruby
37
+ # require utilities which would be used in ruby placeholders
38
+ require 'pathname'
39
+ require 'uri'
40
+ require 'cgi'
41
+ RubyPlaceholderExpander.new(log)
42
+ else
43
+ PlaceholderExpander.new(log)
44
+ end
45
+
46
+ @hostname = Socket.gethostname
47
+ end
48
+
49
+ def emit(tag, es, chain)
50
+ tag_parts = tag.split('.')
51
+ tag_prefix = tag_prefix(tag_parts)
52
+ tag_suffix = tag_suffix(tag_parts)
53
+ placeholders = {
54
+ 'tag' => tag,
55
+ 'tags' => tag_parts,
56
+ 'tag_parts' => tag_parts,
57
+ 'tag_prefix' => tag_prefix,
58
+ 'tag_suffix' => tag_suffix,
59
+ 'hostname' => @hostname,
60
+ }
61
+ last_record = nil
62
+ es.each {|time, record|
63
+ last_record = record # for debug log
64
+ new_tag, new_record = reform(@tag, time, record, placeholders)
65
+ Engine.emit(new_tag, time, new_record)
66
+ }
67
+ chain.next
68
+ rescue => e
69
+ log.warn "remove_empty: #{e.class} #{e.message} #{e.backtrace.first}"
70
+ log.debug "remove_empty: tag:#{@tag} map:#{@map} record:#{last_record} placeholders:#{placeholders}"
71
+ end
72
+
73
+ private
74
+
75
+ def reform(tag, time, record, opts)
76
+ @placeholder_expander.prepare_placeholders(time, record, opts)
77
+ new_tag = @placeholder_expander.expand(tag)
78
+
79
+ new_record = record.dup
80
+ new_record.each_key do |k|
81
+ if new_record[k] == ""
82
+ new_record.delete(k)
83
+ end
84
+ end
85
+
86
+ [new_tag, new_record]
87
+ end
88
+
89
+ def tag_prefix(tag_parts)
90
+ return [] if tag_parts.empty?
91
+ tag_prefix = [tag_parts.first]
92
+ 1.upto(tag_parts.size-1).each do |i|
93
+ tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
94
+ end
95
+ tag_prefix
96
+ end
97
+
98
+ def tag_suffix(tag_parts)
99
+ return [] if tag_parts.empty?
100
+ rev_tag_parts = tag_parts.reverse
101
+ rev_tag_suffix = [rev_tag_parts.first]
102
+ 1.upto(tag_parts.size-1).each do |i|
103
+ rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
104
+ end
105
+ rev_tag_suffix.reverse
106
+ end
107
+
108
+ class PlaceholderExpander
109
+ attr_reader :placeholders, :log
110
+
111
+ def initialize(log)
112
+ @log = log
113
+ end
114
+
115
+ def prepare_placeholders(time, record, opts)
116
+ placeholders = { '${time}' => Time.at(time).to_s }
117
+ record.each {|key, value| placeholders.store("${#{key}}", value) }
118
+
119
+ opts.each do |key, value|
120
+ if value.kind_of?(Array) # tag_parts, etc
121
+ size = value.size
122
+ value.each_with_index { |v, idx|
123
+ placeholders.store("${#{key}[#{idx}]}", v)
124
+ placeholders.store("${#{key}[#{idx-size}]}", v) # support [-1]
125
+ }
126
+ else # string, interger, float, and others?
127
+ placeholders.store("${#{key}}", value)
128
+ end
129
+ end
130
+
131
+ @placeholders = placeholders
132
+ end
133
+
134
+ def expand(str)
135
+ str.gsub(/(\${[a-z_]+(\[-?[0-9]+\])?}|__[A-Z_]+__)/) {
136
+ log.warn "remove_empty: unknown placeholder `#{$1}` found" unless @placeholders.include?($1)
137
+ @placeholders[$1]
138
+ }
139
+ end
140
+ end
141
+
142
+ class RubyPlaceholderExpander
143
+ attr_reader :placeholders, :log
144
+
145
+ def initialize(log)
146
+ @log = log
147
+ end
148
+
149
+ # Get placeholders as a struct
150
+ #
151
+ # @param [Time] time the time
152
+ # @param [Hash] record the record
153
+ # @param [Hash] opts others
154
+ def prepare_placeholders(time, record, opts)
155
+ struct = UndefOpenStruct.new(record)
156
+ struct.time = Time.at(time)
157
+ opts.each {|key, value| struct.__send__("#{key}=", value) }
158
+ @placeholders = struct
159
+ end
160
+
161
+ # Replace placeholders in a string
162
+ #
163
+ # @param [String] str the string to be replaced
164
+ def expand(str)
165
+ str = str.gsub(/\$\{([^}]+)\}/, '#{\1}') # ${..} => #{..}
166
+ eval "\"#{str}\"", @placeholders.instance_eval { binding }
167
+ end
168
+
169
+ class UndefOpenStruct < OpenStruct
170
+ (Object.instance_methods).each do |m|
171
+ undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-remove-empty
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Chadin Anuwattanaporn
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.10.17
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.10.17
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-nav
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Fluentd plugin to remove empty fields of a event record
84
+ email: chadin@sogamo.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - Gemfile
90
+ - README.md
91
+ - fluent-plugin-remove-empty.gemspec
92
+ - lib/fluent/plugin/out_remove_empty.rb
93
+ homepage: https://github.com/newcmd001/fluent-plugin-remove-empty
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.0.14
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Fluentd plugin to remove empty fields of a event record
117
+ test_files: []