fluent-plugin-mongo 0.7.16 → 0.8.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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