fluent-plugin-mongo 0.7.16 → 0.8.0.rc1

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
  SHA1:
3
- metadata.gz: faea3bdbf1168e203df36000467cfed9b780794e
4
- data.tar.gz: d487ede0674b9df9d980e8c1e390b34f295848ee
3
+ metadata.gz: e5a76dcf9763e4ba6cd2ad37a15b1f5b3145d31e
4
+ data.tar.gz: 17f1414c1edf96ae7009ad701815b2f120eb6018
5
5
  SHA512:
6
- metadata.gz: 4d5b3df91a3ec58b00db0ab47fd23adbc6fc88341de31772c463c437c93ef091a72ad530282e626383c565a5352f975cee03406c3ca2b68fae230eed51318553
7
- data.tar.gz: 088e23c4a719fd7081e867f8b7baf23fea93f9e326e5ce7223780b8c0e5d86b50dc3322081900dad71073df5ad5bdd20890e2dfa03b37954ace24639d9f01485
6
+ metadata.gz: 6e45d8d167be9f710635f207edde89c8b2962f7ee16a59f34eb406617c6839ba1021ced2ae508c8450ad36f4e2a8d9475eb53020ecc4984329615105f3a3d87b
7
+ data.tar.gz: 2bbeb260a265b4fd040577862d8b39b72b7d3045c5e2083f758671a80eb8da1a440f6e2c5b3dd8ec1ecfde9043796a46039a82935c32279ff87f4d7e5c7a8e2f
data/.travis.yml CHANGED
@@ -10,12 +10,15 @@ gemfile:
10
10
  - Gemfile
11
11
  - Gemfile.v0.12
12
12
 
13
+ services:
14
+ - mongodb
15
+
13
16
  before_install:
14
17
  - gem update bundler
15
18
  before_script:
16
19
  - git submodule update -i
17
20
 
18
- script: mongod=mongod bundle exec rake test
21
+ script: bundle exec rake test
19
22
 
20
23
  matrix:
21
24
  allow_failures:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.16
1
+ 0.8.0.rc1
data/bin/mongo-tail CHANGED
@@ -8,11 +8,11 @@ require 'json'
8
8
  require 'mongo'
9
9
 
10
10
  TailConfig = {
11
- :d => 'fluent',
12
- :c => 'out_mongo_backup',
13
- :h => 'localhost',
14
- :p => 27017,
15
- :n => 10
11
+ d: 'fluent',
12
+ c: 'out_mongo_backup',
13
+ h: 'localhost',
14
+ p: 27017,
15
+ n: 10
16
16
  }
17
17
 
18
18
  OptionParser.new { |opt|
@@ -28,51 +28,58 @@ OptionParser.new { |opt|
28
28
  opt.parse!(ARGV)
29
29
  }
30
30
 
31
+ def get_client_options(conf)
32
+ client_options = {}
33
+ client_options[:database] = conf[:d]
34
+ client_options
35
+ end
36
+
37
+ def get_collection_options
38
+ collection_options = {}
39
+ collection_options[:capped] = true
40
+ collection_options
41
+ end
42
+
31
43
  def get_capped_collection(conf)
32
- db = Mongo::MongoClient.new(conf[:h], conf[:p]).db(conf[:d])
33
- if db.collection_names.include?(conf[:c])
34
- collection = db.collection(conf[:c])
35
- if collection.capped?
36
- collection
37
- else
38
- puts "#{conf[:c]} is not capped. mongo-tail can not tail normal collection."
39
- end
44
+ client_options = get_client_options(conf)
45
+ collection_options = get_collection_options
46
+ client = Mongo::Client.new(["#{conf[:h]}:#{conf[:p]}"], client_options)
47
+ collection = client["#{conf[:c]}", collection_options]
48
+ if collection.capped?
49
+ collection
40
50
  else
41
- puts "#{conf[:c]} not found: server = #{conf[:h]}:#{conf[:p]}"
51
+ puts "#{conf[:c]} is not capped. mongo-tail can not tail normal collection."
42
52
  end
43
53
  end
44
54
 
45
- def create_cursor_conf(collection, conf)
55
+ def create_skip_number(collection, conf)
46
56
  skip = collection.count - conf[:n]
47
- cursor_conf = {}
48
- cursor_conf[:skip] = skip if skip > 0
49
- cursor_conf
57
+ skip
50
58
  end
51
59
 
52
60
  def tail_n(collection, conf)
53
- collection.find({}, create_cursor_conf(collection, conf)).each { |doc|
61
+ collection.find().skip(create_skip_number(collection, conf)).each {|doc|
54
62
  puts doc.to_json
55
63
  }
56
64
  end
57
65
 
58
66
  def tail_forever(collection, conf)
59
- cursor_conf = create_cursor_conf(collection, conf)
60
- cursor_conf[:tailable] = true
61
-
62
- cursor = Mongo::Cursor.new(collection, cursor_conf)
63
67
  loop {
64
- # TODO: Check more detail of cursor state if needed
65
- cursor = Mongo::Cursor.new(collection, cursor_conf) unless cursor.alive?
68
+ option['_id'] = {'$gt' => BSON::ObjectId(@last_id)} if @last_id
66
69
 
67
- if doc = cursor.next_document
68
- STDOUT.puts doc.to_json
69
- STDOUT.flush
70
+ documents = collection.find(option)
71
+ if documents.count >= 1
72
+ documents.each {|doc|
73
+ STDOUT.puts doc.to_json
74
+ STDOUT.flush
75
+ if id = doc.delete('_id')
76
+ @last_id = id.to_s
77
+ end
78
+ }
70
79
  else
71
80
  sleep 1
72
81
  end
73
82
  }
74
- rescue
75
- # ignore Mongo::OperationFailuer at CURSOR_NOT_FOUND
76
83
  end
77
84
 
78
85
  exit unless collection = get_capped_collection(TailConfig)
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ['lib']
19
19
 
20
20
  gem.add_dependency "fluentd", [">= 0.10.58", "< 2"]
21
- gem.add_dependency "mongo", "~> 1.9"
21
+ gem.add_runtime_dependency "mongo", "~> 2.2.0"
22
22
  gem.add_development_dependency "rake", ">= 0.9.2"
23
23
  gem.add_development_dependency "simplecov", ">= 0.5.4"
24
24
  gem.add_development_dependency "rr", ">= 1.0.0"
@@ -4,38 +4,56 @@ module Fluent
4
4
  class MongoTailInput < Input
5
5
  Plugin.register_input('mongo_tail', self)
6
6
 
7
- require 'fluent/plugin/mongo_util'
8
- include MongoUtil
9
-
10
- config_param :database, :string, :default => nil
11
- config_param :collection, :string
12
- config_param :host, :string, :default => 'localhost'
13
- config_param :port, :integer, :default => 27017
14
- config_param :wait_time, :integer, :default => 1
15
- config_param :url, :string, :default => nil
16
-
17
- config_param :tag, :string, :default => nil
18
- config_param :tag_key, :string, :default => nil
19
- config_param :time_key, :string, :default => nil
20
- config_param :time_format, :string, :default => nil
21
- config_param :object_id_keys, :array, :default => nil
22
-
23
- # To store last ObjectID
24
- config_param :id_store_file, :string, :default => nil
25
- config_param :id_store_collection, :string, :default => nil
26
-
27
- # SSL connection
28
- config_param :ssl, :bool, :default => false
29
-
30
7
  unless method_defined?(:log)
31
8
  define_method(:log) { $log }
32
9
  end
33
10
 
11
+ # Define `router` method of v0.12 to support v0.10 or earlier
12
+ unless method_defined?(:router)
13
+ define_method("router") { ::Fluent::Engine }
14
+ end
15
+
16
+ require 'fluent/plugin/mongo_auth'
17
+ include MongoAuthParams
18
+ include MongoAuth
19
+ require 'fluent/plugin/logger_support'
20
+ include LoggerSupport
21
+
22
+ desc "MongoDB database"
23
+ config_param :database, :string, default: nil
24
+ desc "MongoDB collection"
25
+ config_param :collection, :string
26
+ desc "MongoDB host"
27
+ config_param :host, :string, default: 'localhost'
28
+ desc "MongoDB port"
29
+ config_param :port, :integer, default: 27017
30
+ desc "Tailing interval"
31
+ config_param :wait_time, :integer, default: 1
32
+ desc "MongoDB node URL"
33
+ config_param :url, :string, default: nil
34
+
35
+ desc "Input tag"
36
+ config_param :tag, :string, default: nil
37
+ desc "Treat key as tag"
38
+ config_param :tag_key, :string, default: nil
39
+ desc "Treat key as time"
40
+ config_param :time_key, :string, default: nil
41
+ desc "Time format"
42
+ config_param :time_format, :string, default: nil
43
+ config_param :object_id_keys, :array, default: nil
44
+
45
+ desc "To store last ObjectID"
46
+ config_param :id_store_file, :string, default: nil
47
+
48
+ desc "SSL connection"
49
+ config_param :ssl, :bool, default: false
50
+
34
51
  def initialize
35
52
  super
36
53
  require 'mongo'
37
54
  require 'bson'
38
55
 
56
+ @client_options = {}
39
57
  @connection_options = {}
40
58
  end
41
59
 
@@ -54,86 +72,72 @@ module Fluent
54
72
  raise ConfigError, "One of 'database' or 'url' must be specified"
55
73
  end
56
74
 
57
- @last_id = get_last_id
75
+ @last_id = @id_store_file ? get_last_id : nil
58
76
  @connection_options[:ssl] = @ssl
59
77
 
60
- $log.debug "Setup mongo_tail configuration: mode = #{@id_store_file || @id_store_collection ? 'persistent' : 'non-persistent'}, last_id = #{@last_id}"
78
+ configure_logger(@mongo_log_level)
61
79
  end
62
80
 
63
81
  def start
64
82
  super
65
- open_id_storage
66
- @client = get_capped_collection
83
+
84
+ @file = get_id_store_file if @id_store_file
85
+ @collection = get_collection
86
+ # Resume tailing from last inserted id.
87
+ # Because tailable option is obsoleted since mongo driver 2.0.
88
+ @last_id = get_last_inserted_id if !@id_store_file and get_last_inserted_id
67
89
  @thread = Thread.new(&method(:run))
68
90
  end
69
91
 
70
92
  def shutdown
71
- save_last_id(@last_id) unless @last_id
72
- close_id_storage
93
+ if @id_store_file
94
+ save_last_id
95
+ @file.close
96
+ end
73
97
 
74
98
  @stop = true
75
99
  @thread.join
76
- @client.db.connection.close
100
+ @client.close
101
+
77
102
  super
78
103
  end
79
104
 
80
105
  def run
81
106
  loop {
82
- cursor = Mongo::Cursor.new(@client, cursor_conf)
107
+ option = {}
83
108
  begin
84
109
  loop {
85
110
  return if @stop
86
-
87
- cursor = Mongo::Cursor.new(@client, cursor_conf) unless cursor.alive?
88
- if doc = cursor.next_document
89
- process_document(doc)
111
+
112
+ option['_id'] = {'$gt' => BSON::ObjectId(@last_id)} if @last_id
113
+ documents = @collection.find(option)
114
+ if documents.count >= 1
115
+ process_documents(documents)
90
116
  else
91
117
  sleep @wait_time
92
118
  end
93
119
  }
94
120
  rescue
95
- # ignore Mongo::OperationFailuer at CURSOR_NOT_FOUND
121
+ # ignore Exceptions
96
122
  end
97
123
  }
98
124
  end
99
125
 
100
126
  private
101
127
 
102
- def get_capped_collection
103
- begin
104
- db = get_database
105
- raise ConfigError, "'#{database_name}.#{@collection}' not found: node = #{node_string}" unless db.collection_names.include?(@collection)
106
- collection = db.collection(@collection)
107
- raise ConfigError, "'#{database_name}.#{@collection}' is not capped: node = #{node_string}" unless collection.capped?
108
- collection
109
- rescue Mongo::ConnectionFailure => e
110
- log.fatal "Failed to connect to 'mongod'. Please restart 'fluentd' after 'mongod' started: #{e}"
111
- exit!
112
- rescue Mongo::OperationFailure => e
113
- log.fatal "Operation failed. Probably, 'mongod' needs an authentication: #{e}"
114
- exit!
115
- end
116
- end
117
-
118
- def get_database
119
- case
120
- when @database
121
- authenticate(Mongo::Connection.new(@host, @port, @connection_options).db(@database))
122
- when @url
123
- parser = Mongo::URIParser.new(@url)
124
- parser.connection.db(parser.db_name)
125
- end
128
+ def client
129
+ @client_options[:database] = @database
130
+ @client_options[:user] = @user if @user
131
+ @client_options[:password] = @password if @password
132
+ Mongo::Client.new(["#{node_string}"], @client_options)
126
133
  end
127
-
128
- def database_name
129
- case
130
- when @database
131
- @database
132
- when @url
133
- Mongo::URIParser.new(@url).db_name
134
- end
134
+
135
+ def get_collection
136
+ @client = client
137
+ @client = authenticate(@client)
138
+ @client["#{@collection}"]
135
139
  end
136
-
140
+
137
141
  def node_string
138
142
  case
139
143
  when @database
@@ -143,87 +147,67 @@ module Fluent
143
147
  end
144
148
  end
145
149
 
146
- def process_document(doc)
147
- time = if @time_key
148
- t = doc.delete(@time_key)
149
- t.nil? ? Engine.now : t.to_i
150
- else
151
- Engine.now
152
- end
153
- tag = if @tag_key
154
- t = doc.delete(@tag_key)
155
- t.nil? ? 'mongo.missing_tag' : t
156
- else
157
- @tag
158
- end
159
- if @object_id_keys
160
- @object_id_keys.each { |id_key|
161
- doc[id_key] = doc[id_key].to_s
162
- }
163
- end
164
-
165
- if id = doc.delete('_id')
166
- @last_id = id.to_s
167
- doc['_id_str'] = @last_id
168
- save_last_id(@last_id)
169
- end
170
-
171
- # Should use MultiEventStream?
172
- router.emit(tag, time, doc)
173
- end
150
+ def process_documents(documents)
151
+ es = MultiEventStream.new
152
+ documents.each {|doc|
153
+ time = if @time_key
154
+ t = doc.delete(@time_key)
155
+ t.nil? ? Engine.now : t.to_i
156
+ else
157
+ Engine.now
158
+ end
159
+ tag = if @tag_key
160
+ t = doc.delete(@tag_key)
161
+ t.nil? ? 'mongo.missing_tag' : t
162
+ else
163
+ @tag
164
+ end
165
+ if @object_id_keys
166
+ @object_id_keys.each {|id_key|
167
+ doc[id_key] = doc[id_key].to_s
168
+ }
169
+ end
174
170
 
175
- def cursor_conf
176
- conf = {}
177
- conf[:tailable] = true
178
- conf[:selector] = {'_id' => {'$gt' => BSON::ObjectId(@last_id)}} if @last_id
179
- conf
171
+ if id = doc.delete('_id')
172
+ @last_id = id.to_s
173
+ doc['_id_str'] = @last_id
174
+ save_last_id if @id_store_file
175
+ end
176
+ es.add(time, doc)
177
+ }
178
+ router.emit_stream(tag, es)
180
179
  end
181
180
 
182
- # following methods are used to read/write last_id
183
-
184
- def open_id_storage
185
- if @id_store_file
186
- @id_storage = File.open(@id_store_file, 'w')
187
- @id_storege.sync
188
- end
189
-
190
- if @id_store_collection
191
- @id_storage = get_database.collection(@id_store_collection)
181
+ def get_last_inserted_id
182
+ last_inserted_id = nil
183
+ documents = @collection.find()
184
+ if documents.count >= 1
185
+ documents.each {|doc|
186
+ if id = doc.delete('_id')
187
+ last_inserted_id = id
188
+ end
189
+ }
192
190
  end
191
+ last_inserted_id
193
192
  end
194
-
195
- def close_id_storage
196
- if @id_storage.is_a?(File)
197
- @id_storage.close
198
- end
193
+
194
+ def get_id_store_file
195
+ file = File.open(@id_store_file, 'w')
196
+ file.sync
197
+ file
199
198
  end
200
199
 
201
200
  def get_last_id
202
- begin
203
- if @id_store_file && File.exist?(@id_store_file)
204
- return BSON::ObjectId(File.read(@id_store_file)).to_s
205
- end
206
-
207
- if @id_store_collection
208
- collection = get_database.collection(@id_store_collection)
209
- count = collection.find.count
210
- doc = collection.find.skip(count - 1).limit(1).first
211
- return doc && doc["last_id"]
212
- end
213
- rescue
201
+ if File.exist?(@id_store_file)
202
+ BSON::ObjectId(File.read(@id_store_file)).to_s rescue nil
203
+ else
214
204
  nil
215
205
  end
216
206
  end
217
207
 
218
- def save_last_id(last_id)
219
- if @id_storage.is_a?(File)
220
- @id_storage.pos = 0
221
- @id_storage.write(last_id)
222
- end
223
-
224
- if @id_storage.is_a?(Mongo::Collection)
225
- @id_storage.insert("last_id" => last_id)
226
- end
208
+ def save_last_id
209
+ @file.pos = 0
210
+ @file.write(@last_id)
227
211
  end
228
212
  end
229
213
  end