fluent-plugin-mongo 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ChangeLog +9 -2
- data/VERSION +1 -1
- data/lib/fluent/plugin/in_mongo_tail.rb +118 -122
- data/lib/fluent/plugin/out_mongo.rb +187 -183
- data/lib/fluent/plugin/out_mongo_replset.rb +56 -60
- data/lib/fluent/plugin/out_mongo_tag_collection.rb +10 -14
- metadata +13 -32
- data/lib/fluent/plugin/out_mongo_backup.rb +0 -28
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 223d88d3a35d00c18254bda1ffe8320900a5e76a
|
4
|
+
data.tar.gz: 5581a2106b77d3797dd6f0e67310a7e21305aafa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a0b6292750fb0bcad9079ee182591fa6b0ac35d009931b240b7d5403890f22955df8f7f45782b476f1160e10ebf2f92b5e19dc525b937e151eb200d7de8e1aaa
|
7
|
+
data.tar.gz: 8ff33a0383a02d5b6b34418b9738a1afbd527eaaab67b33e9bc334e73854d3859eaaa4386215bab455fa0638ce6def3a6822b92a516b7f68a596d2a9a34fef4e
|
data/ChangeLog
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
Release 0.7.
|
1
|
+
Release 0.7.1 - 2013/07/31
|
2
|
+
|
3
|
+
* Fix incomprehensible code indent
|
4
|
+
* Remove mongo_backup output
|
5
|
+
* Fix getting version from mongod for broken mongod support
|
6
|
+
|
7
|
+
|
8
|
+
Release 0.7.0 - 2013/03/20
|
2
9
|
|
3
10
|
* Upgrade mongo gem least version to 1.8
|
4
11
|
* Upgrade fluentd gem least version to 0.10.9
|
@@ -7,7 +14,7 @@ Release 0.7.0 - 2012/03/20
|
|
7
14
|
* Change buffer_chunk_limit to 8MB when mongod version is 1.8 or later.
|
8
15
|
|
9
16
|
|
10
|
-
Release 0.6.13 -
|
17
|
+
Release 0.6.13 - 2013/01/15
|
11
18
|
|
12
19
|
* Add exclude_broken_fields config to output plugins
|
13
20
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.1
|
@@ -1,146 +1,142 @@
|
|
1
1
|
module Fluent
|
2
|
+
class MongoTailInput < Input
|
3
|
+
Plugin.register_input('mongo_tail', self)
|
4
|
+
|
5
|
+
require 'fluent/plugin/mongo_util'
|
6
|
+
include MongoUtil
|
7
|
+
|
8
|
+
config_param :database, :string
|
9
|
+
config_param :collection, :string
|
10
|
+
config_param :host, :string, :default => 'localhost'
|
11
|
+
config_param :port, :integer, :default => 27017
|
12
|
+
config_param :wait_time, :integer, :default => 1
|
13
|
+
|
14
|
+
config_param :tag, :string, :default => nil
|
15
|
+
config_param :tag_key, :string, :default => nil
|
16
|
+
config_param :time_key, :string, :default => nil
|
17
|
+
config_param :time_format, :string, :default => nil
|
18
|
+
|
19
|
+
# To store last ObjectID
|
20
|
+
config_param :id_store_file, :string, :default => nil
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
super
|
24
|
+
require 'mongo'
|
25
|
+
require 'bson'
|
26
|
+
end
|
2
27
|
|
28
|
+
def configure(conf)
|
29
|
+
super
|
3
30
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require 'fluent/plugin/mongo_util'
|
8
|
-
include MongoUtil
|
9
|
-
|
10
|
-
config_param :database, :string
|
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
|
31
|
+
if !@tag and !@tag_key
|
32
|
+
raise ConfigError, "'tag' or 'tag_key' option is required on mongo_tail input"
|
33
|
+
end
|
15
34
|
|
16
|
-
|
17
|
-
config_param :tag_key, :string, :default => nil
|
18
|
-
config_param :time_key, :string, :default => nil
|
19
|
-
config_param :time_format, :string, :default => nil
|
35
|
+
@last_id = @id_store_file ? get_last_id : nil
|
20
36
|
|
21
|
-
|
22
|
-
|
37
|
+
$log.debug "Setup mongo_tail configuration: mode = #{@id_store_file ? 'persistent' : 'non-persistent'}"
|
38
|
+
end
|
23
39
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
40
|
+
def start
|
41
|
+
super
|
42
|
+
@file = get_id_store_file if @id_store_file
|
43
|
+
@client = get_capped_collection
|
44
|
+
@thread = Thread.new(&method(:run))
|
45
|
+
end
|
29
46
|
|
30
|
-
|
31
|
-
|
47
|
+
def shutdown
|
48
|
+
if @id_store_file
|
49
|
+
save_last_id
|
50
|
+
@file.close
|
51
|
+
end
|
32
52
|
|
33
|
-
|
34
|
-
|
53
|
+
@thread.join
|
54
|
+
@client.db.connection.close
|
55
|
+
super
|
35
56
|
end
|
36
57
|
|
37
|
-
|
58
|
+
def run
|
59
|
+
loop {
|
60
|
+
tailoop(Mongo::Cursor.new(@client, cursor_conf))
|
61
|
+
}
|
62
|
+
end
|
38
63
|
|
39
|
-
|
40
|
-
|
64
|
+
private
|
65
|
+
|
66
|
+
def get_capped_collection
|
67
|
+
begin
|
68
|
+
db = authenticate(Mongo::Connection.new(@host, @port).db(@database))
|
69
|
+
raise ConfigError, "'#{@database}.#{@collection}' not found: node = #{@host}:#{@port}" unless db.collection_names.include?(@collection)
|
70
|
+
collection = db.collection(@collection)
|
71
|
+
raise ConfigError, "'#{@database}.#{@collection}' is not capped: node = #{@host}:#{@port}" unless collection.capped?
|
72
|
+
collection
|
73
|
+
rescue Mongo::ConnectionFailure => e
|
74
|
+
$log.fatal "Failed to connect to 'mongod'. Please restart 'fluentd' after 'mongod' started: #{e}"
|
75
|
+
exit!
|
76
|
+
rescue Mongo::OperationFailure => e
|
77
|
+
$log.fatal "Operation failed. Probably, 'mongod' needs an authentication: #{e}"
|
78
|
+
exit!
|
79
|
+
end
|
80
|
+
end
|
41
81
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
82
|
+
def tailoop(cursor)
|
83
|
+
loop {
|
84
|
+
cursor = Mongo::Cursor.new(@client, cursor_conf) unless cursor.alive?
|
85
|
+
if doc = cursor.next_document
|
86
|
+
time = if @time_key
|
87
|
+
t = doc.delete(@time_key)
|
88
|
+
t.nil? ? Engine.now : t.to_i
|
89
|
+
else
|
90
|
+
Engine.now
|
91
|
+
end
|
92
|
+
tag = if @tag_key
|
93
|
+
t = doc.delete(@tag_key)
|
94
|
+
t.nil? ? 'mongo.missing_tag' : t
|
95
|
+
else
|
96
|
+
@tag
|
97
|
+
end
|
98
|
+
if id = doc.delete('_id')
|
99
|
+
@last_id = id.to_s
|
100
|
+
doc['_id_str'] = @last_id
|
101
|
+
save_last_id if @id_store_file
|
102
|
+
end
|
103
|
+
|
104
|
+
# Should use MultiEventStream?
|
105
|
+
Engine.emit(tag, time, doc)
|
106
|
+
else
|
107
|
+
sleep @wait_time
|
108
|
+
end
|
109
|
+
}
|
110
|
+
rescue
|
111
|
+
# ignore Mongo::OperationFailuer at CURSOR_NOT_FOUND
|
112
|
+
end
|
48
113
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
@
|
114
|
+
def cursor_conf
|
115
|
+
conf = {}
|
116
|
+
conf[:tailable] = true
|
117
|
+
conf[:selector] = {'_id' => {'$gt' => BSON::ObjectId(@last_id)}} if @last_id
|
118
|
+
conf
|
53
119
|
end
|
54
120
|
|
55
|
-
|
56
|
-
@client.db.connection.close
|
57
|
-
super
|
58
|
-
end
|
121
|
+
# following methods are used when id_store_file is true
|
59
122
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def get_capped_collection
|
69
|
-
begin
|
70
|
-
db = authenticate(Mongo::Connection.new(@host, @port).db(@database))
|
71
|
-
raise ConfigError, "'#{@database}.#{@collection}' not found: node = #{@host}:#{@port}" unless db.collection_names.include?(@collection)
|
72
|
-
collection = db.collection(@collection)
|
73
|
-
raise ConfigError, "'#{@database}.#{@collection}' is not capped: node = #{@host}:#{@port}" unless collection.capped?
|
74
|
-
collection
|
75
|
-
rescue Mongo::ConnectionFailure => e
|
76
|
-
$log.fatal "Failed to connect to 'mongod'. Please restart 'fluentd' after 'mongod' started: #{e}"
|
77
|
-
exit!
|
78
|
-
rescue Mongo::OperationFailure => e
|
79
|
-
$log.fatal "Operation failed. Probably, 'mongod' needs an authentication: #{e}"
|
80
|
-
exit!
|
123
|
+
def get_id_store_file
|
124
|
+
file = File.open(@id_store_file, 'w')
|
125
|
+
file.sync
|
126
|
+
file
|
81
127
|
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def tailoop(cursor)
|
85
|
-
loop {
|
86
|
-
cursor = Mongo::Cursor.new(@client, cursor_conf) unless cursor.alive?
|
87
|
-
if doc = cursor.next_document
|
88
|
-
time = if @time_key
|
89
|
-
t = doc.delete(@time_key)
|
90
|
-
t.nil? ? Engine.now : t.to_i
|
91
|
-
else
|
92
|
-
Engine.now
|
93
|
-
end
|
94
|
-
tag = if @tag_key
|
95
|
-
t = doc.delete(@tag_key)
|
96
|
-
t.nil? ? 'mongo.missing_tag' : t
|
97
|
-
else
|
98
|
-
@tag
|
99
|
-
end
|
100
|
-
if id = doc.delete('_id')
|
101
|
-
@last_id = id.to_s
|
102
|
-
doc['_id_str'] = @last_id
|
103
|
-
save_last_id if @id_store_file
|
104
|
-
end
|
105
128
|
|
106
|
-
|
107
|
-
|
129
|
+
def get_last_id
|
130
|
+
if File.exist?(@id_store_file)
|
131
|
+
BSON::ObjectId(File.read(@id_store_file)).to_s rescue nil
|
108
132
|
else
|
109
|
-
|
133
|
+
nil
|
110
134
|
end
|
111
|
-
}
|
112
|
-
rescue
|
113
|
-
# ignore Mongo::OperationFailuer at CURSOR_NOT_FOUND
|
114
|
-
end
|
115
|
-
|
116
|
-
def cursor_conf
|
117
|
-
conf = {}
|
118
|
-
conf[:tailable] = true
|
119
|
-
conf[:selector] = {'_id' => {'$gt' => BSON::ObjectId(@last_id)}} if @last_id
|
120
|
-
conf
|
121
|
-
end
|
122
|
-
|
123
|
-
# following methods are used when id_store_file is true
|
124
|
-
|
125
|
-
def get_id_store_file
|
126
|
-
file = File.open(@id_store_file, 'w')
|
127
|
-
file.sync
|
128
|
-
file
|
129
|
-
end
|
130
|
-
|
131
|
-
def get_last_id
|
132
|
-
if File.exist?(@id_store_file)
|
133
|
-
BSON::ObjectId(File.read(@id_store_file)).to_s rescue nil
|
134
|
-
else
|
135
|
-
nil
|
136
135
|
end
|
137
|
-
end
|
138
136
|
|
139
|
-
|
140
|
-
|
141
|
-
|
137
|
+
def save_last_id
|
138
|
+
@file.pos = 0
|
139
|
+
@file.write(@last_id)
|
140
|
+
end
|
142
141
|
end
|
143
142
|
end
|
144
|
-
|
145
|
-
|
146
|
-
end
|
@@ -1,231 +1,235 @@
|
|
1
1
|
module Fluent
|
2
|
+
class MongoOutput < BufferedOutput
|
3
|
+
Plugin.register_output('mongo', self)
|
2
4
|
|
5
|
+
require 'fluent/plugin/mongo_util'
|
6
|
+
include MongoUtil
|
3
7
|
|
4
|
-
|
5
|
-
|
8
|
+
include SetTagKeyMixin
|
9
|
+
config_set_default :include_tag_key, false
|
6
10
|
|
7
|
-
|
8
|
-
|
11
|
+
include SetTimeKeyMixin
|
12
|
+
config_set_default :include_time_key, true
|
9
13
|
|
10
|
-
|
11
|
-
|
14
|
+
config_param :database, :string
|
15
|
+
config_param :collection, :string, :default => 'untagged'
|
16
|
+
config_param :host, :string, :default => 'localhost'
|
17
|
+
config_param :port, :integer, :default => 27017
|
18
|
+
config_param :ignore_invalid_record, :bool, :default => false
|
19
|
+
config_param :disable_collection_check, :bool, :default => nil
|
20
|
+
config_param :exclude_broken_fields, :string, :default => nil
|
21
|
+
config_param :write_concern, :integer, :default => nil
|
12
22
|
|
13
|
-
|
14
|
-
|
23
|
+
# tag mapping mode
|
24
|
+
config_param :tag_mapped, :bool, :default => false
|
25
|
+
config_param :remove_tag_prefix, :string, :default => nil
|
15
26
|
|
16
|
-
|
17
|
-
config_param :collection, :string, :default => 'untagged'
|
18
|
-
config_param :host, :string, :default => 'localhost'
|
19
|
-
config_param :port, :integer, :default => 27017
|
20
|
-
config_param :ignore_invalid_record, :bool, :default => false
|
21
|
-
config_param :disable_collection_check, :bool, :default => nil
|
22
|
-
config_param :exclude_broken_fields, :string, :default => nil
|
23
|
-
config_param :write_concern, :integer, :default => nil
|
27
|
+
attr_reader :collection_options, :connection_options
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
29
|
+
def initialize
|
30
|
+
super
|
31
|
+
require 'mongo'
|
32
|
+
require 'msgpack'
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
require 'mongo'
|
34
|
-
require 'msgpack'
|
34
|
+
@clients = {}
|
35
|
+
@connection_options = {}
|
36
|
+
@collection_options = {:capped => false}
|
37
|
+
end
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
@collection_options = {:capped => false}
|
39
|
-
end
|
39
|
+
def configure(conf)
|
40
|
+
super
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
if conf.has_key?('tag_mapped')
|
43
|
+
@tag_mapped = true
|
44
|
+
@disable_collection_check = true if @disable_collection_check.nil?
|
45
|
+
else
|
46
|
+
@disable_collection_check = false if @disable_collection_check.nil?
|
47
|
+
end
|
48
|
+
raise ConfigError, "normal mode requires collection parameter" if !@tag_mapped and !conf.has_key?('collection')
|
43
49
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
@disable_collection_check = false if @disable_collection_check.nil?
|
49
|
-
end
|
50
|
-
raise ConfigError, "normal mode requires collection parameter" if !@tag_mapped and !conf.has_key?('collection')
|
50
|
+
if remove_tag_prefix = conf['remove_tag_prefix']
|
51
|
+
@remove_tag_prefix = Regexp.new('^' + Regexp.escape(remove_tag_prefix))
|
52
|
+
end
|
51
53
|
|
52
|
-
|
53
|
-
@remove_tag_prefix = Regexp.new('^' + Regexp.escape(remove_tag_prefix))
|
54
|
-
end
|
54
|
+
@exclude_broken_fields = @exclude_broken_fields.split(',') if @exclude_broken_fields
|
55
55
|
|
56
|
-
|
56
|
+
if conf.has_key?('capped')
|
57
|
+
raise ConfigError, "'capped_size' parameter is required on <store> of Mongo output" unless conf.has_key?('capped_size')
|
58
|
+
@collection_options[:capped] = true
|
59
|
+
@collection_options[:size] = Config.size_value(conf['capped_size'])
|
60
|
+
@collection_options[:max] = Config.size_value(conf['capped_max']) if conf.has_key?('capped_max')
|
61
|
+
end
|
57
62
|
|
58
|
-
|
59
|
-
raise ConfigError, "'capped_size' parameter is required on <store> of Mongo output" unless conf.has_key?('capped_size')
|
60
|
-
@collection_options[:capped] = true
|
61
|
-
@collection_options[:size] = Config.size_value(conf['capped_size'])
|
62
|
-
@collection_options[:max] = Config.size_value(conf['capped_max']) if conf.has_key?('capped_max')
|
63
|
-
end
|
63
|
+
@connection_options[:w] = @write_concern unless @write_concern.nil?
|
64
64
|
|
65
|
-
|
65
|
+
# MongoDB uses BSON's Date for time.
|
66
|
+
def @timef.format_nocache(time)
|
67
|
+
time
|
68
|
+
end
|
66
69
|
|
67
|
-
|
68
|
-
def @timef.format_nocache(time)
|
69
|
-
time
|
70
|
+
$log.debug "Setup mongo configuration: mode = #{@tag_mapped ? 'tag mapped' : 'normal'}"
|
70
71
|
end
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
def start
|
76
|
-
# Non tag mapped mode, we can check collection configuration before server start.
|
77
|
-
get_or_create_collection(@collection) unless @tag_mapped
|
73
|
+
def start
|
74
|
+
# Non tag mapped mode, we can check collection configuration before server start.
|
75
|
+
get_or_create_collection(@collection) unless @tag_mapped
|
78
76
|
|
79
|
-
|
80
|
-
|
77
|
+
# From configure for avoding complex method dependency...
|
78
|
+
@buffer.buffer_chunk_limit = available_buffer_chunk_limit
|
81
79
|
|
82
|
-
|
83
|
-
|
80
|
+
super
|
81
|
+
end
|
84
82
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
83
|
+
def shutdown
|
84
|
+
# Mongo::Connection checks alive or closed myself
|
85
|
+
@clients.values.each { |client| client.db.connection.close }
|
86
|
+
super
|
87
|
+
end
|
90
88
|
|
91
|
-
|
92
|
-
|
93
|
-
|
89
|
+
def format(tag, time, record)
|
90
|
+
[time, record].to_msgpack
|
91
|
+
end
|
94
92
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
93
|
+
def emit(tag, es, chain)
|
94
|
+
# TODO: Should replacement using eval in configure?
|
95
|
+
if @tag_mapped
|
96
|
+
super(tag, es, chain, tag)
|
97
|
+
else
|
98
|
+
super(tag, es, chain)
|
99
|
+
end
|
101
100
|
end
|
102
|
-
end
|
103
101
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
102
|
+
def write(chunk)
|
103
|
+
# TODO: See emit comment
|
104
|
+
collection_name = @tag_mapped ? chunk.key : @collection
|
105
|
+
operate(get_or_create_collection(collection_name), collect_records(chunk))
|
106
|
+
end
|
109
107
|
|
110
|
-
|
108
|
+
private
|
111
109
|
|
112
|
-
|
113
|
-
|
110
|
+
INSERT_ARGUMENT = {:collect_on_error => true}
|
111
|
+
BROKEN_DATA_KEY = '__broken_data'
|
114
112
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
113
|
+
def operate(collection, records)
|
114
|
+
begin
|
115
|
+
record_ids, error_records = collection.insert(records, INSERT_ARGUMENT)
|
116
|
+
if !@ignore_invalid_record and error_records.size > 0
|
117
|
+
operate_invalid_records(collection, error_records)
|
118
|
+
end
|
119
|
+
rescue Mongo::OperationFailure => e
|
120
|
+
# Probably, all records of _records_ are broken...
|
121
|
+
if e.error_code == 13066 # 13066 means "Message contains no documents"
|
122
|
+
operate_invalid_records(collection, records) unless @ignore_invalid_record
|
123
|
+
else
|
124
|
+
raise e
|
125
|
+
end
|
127
126
|
end
|
127
|
+
records
|
128
128
|
end
|
129
|
-
records
|
130
|
-
end
|
131
129
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
130
|
+
def operate_invalid_records(collection, records)
|
131
|
+
converted_records = records.map { |record|
|
132
|
+
new_record = {}
|
133
|
+
new_record[@tag_key] = record.delete(@tag_key) if @include_tag_key
|
134
|
+
new_record[@time_key] = record.delete(@time_key)
|
135
|
+
if @exclude_broken_fields
|
136
|
+
@exclude_broken_fields.each { |key|
|
137
|
+
new_record[key] = record.delete(key)
|
138
|
+
}
|
139
|
+
end
|
140
|
+
new_record[BROKEN_DATA_KEY] = BSON::Binary.new(Marshal.dump(record))
|
141
|
+
new_record
|
142
|
+
}
|
143
|
+
collection.insert(converted_records)
|
144
|
+
end
|
147
145
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
146
|
+
def collect_records(chunk)
|
147
|
+
records = []
|
148
|
+
chunk.msgpack_each { |time, record|
|
149
|
+
record[@time_key] = Time.at(time || record[@time_key]) if @include_time_key
|
150
|
+
records << record
|
151
|
+
}
|
152
|
+
records
|
153
|
+
end
|
156
154
|
|
157
|
-
|
155
|
+
FORMAT_COLLECTION_NAME_RE = /(^\.+)|(\.+$)/
|
158
156
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
157
|
+
def format_collection_name(collection_name)
|
158
|
+
formatted = collection_name
|
159
|
+
formatted = formatted.gsub(@remove_tag_prefix, '') if @remove_tag_prefix
|
160
|
+
formatted = formatted.gsub(FORMAT_COLLECTION_NAME_RE, '')
|
161
|
+
formatted = @collection if formatted.size == 0 # set default for nil tag
|
162
|
+
formatted
|
163
|
+
end
|
166
164
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
165
|
+
def get_or_create_collection(collection_name)
|
166
|
+
collection_name = format_collection_name(collection_name)
|
167
|
+
return @clients[collection_name] if @clients[collection_name]
|
168
|
+
|
169
|
+
@db ||= get_connection
|
170
|
+
if @db.collection_names.include?(collection_name)
|
171
|
+
collection = @db.collection(collection_name)
|
172
|
+
unless @disable_collection_check
|
173
|
+
capped = collection.capped?
|
174
|
+
unless @collection_options[:capped] == capped # TODO: Verify capped configuration
|
175
|
+
new_mode = format_collection_mode(@collection_options[:capped])
|
176
|
+
old_mode = format_collection_mode(capped)
|
177
|
+
raise ConfigError, "New configuration is different from existing collection: new = #{new_mode}, old = #{old_mode}"
|
178
|
+
end
|
180
179
|
end
|
180
|
+
else
|
181
|
+
collection = @db.create_collection(collection_name, @collection_options)
|
181
182
|
end
|
182
|
-
|
183
|
-
|
183
|
+
|
184
|
+
@clients[collection_name] = collection
|
184
185
|
end
|
185
186
|
|
186
|
-
|
187
|
-
|
187
|
+
def format_collection_mode(mode)
|
188
|
+
mode ? 'capped' : 'normal'
|
189
|
+
end
|
188
190
|
|
189
|
-
|
190
|
-
|
191
|
-
|
191
|
+
def get_connection
|
192
|
+
db = Mongo::MongoClient.new(@host, @port, @connection_options).db(@database)
|
193
|
+
authenticate(db)
|
194
|
+
end
|
192
195
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
196
|
+
# Following limits are heuristic. BSON is sometimes bigger than MessagePack and JSON.
|
197
|
+
LIMIT_BEFORE_v1_8 = 2 * 1024 * 1024 # 2MB = 4MB / 2
|
198
|
+
LIMIT_AFTER_v1_8 = 8 * 1024 * 1024 # 8MB = 16MB / 2
|
199
|
+
|
200
|
+
def available_buffer_chunk_limit
|
201
|
+
begin
|
202
|
+
limit = mongod_version >= "1.8.0" ? LIMIT_AFTER_v1_8 : LIMIT_BEFORE_v1_8
|
203
|
+
rescue Mongo::ConnectionFailure => e
|
204
|
+
$log.fatal "Failed to connect to 'mongod'. Please restart 'fluentd' after 'mongod' started: #{e}"
|
205
|
+
exit!
|
206
|
+
rescue Mongo::OperationFailure => e
|
207
|
+
$log.fatal "Operation failed. Probably, 'mongod' needs an authentication: #{e}"
|
208
|
+
exit!
|
209
|
+
rescue Exception => e
|
210
|
+
$log.warn "mongo unknown error #{e}, set #{LIMIT_BEFORE_v1_8} to chunk limit"
|
211
|
+
limit = LIMIT_BEFORE_v1_8
|
212
|
+
end
|
197
213
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
limit = mongod_version >= "1.8.0" ? LIMIT_AFTER_v1_8 : LIMIT_BEFORE_v1_8
|
205
|
-
rescue Mongo::ConnectionFailure => e
|
206
|
-
$log.fatal "Failed to connect to 'mongod'. Please restart 'fluentd' after 'mongod' started: #{e}"
|
207
|
-
exit!
|
208
|
-
rescue Mongo::OperationFailure => e
|
209
|
-
$log.fatal "Operation failed. Probably, 'mongod' needs an authentication: #{e}"
|
210
|
-
exit!
|
211
|
-
rescue Exception => e
|
212
|
-
$log.warn "mongo unknown error #{e}, set #{LIMIT_BEFORE_v1_8} to chunk limit"
|
213
|
-
limit = LIMIT_BEFORE_v1_8
|
214
|
-
end
|
215
|
-
|
216
|
-
if @buffer.buffer_chunk_limit > limit
|
217
|
-
$log.warn ":buffer_chunk_limit(#{@buffer.buffer_chunk_limit}) is large. Reset :buffer_chunk_limit with #{limit}"
|
218
|
-
limit
|
219
|
-
else
|
220
|
-
@buffer.buffer_chunk_limit
|
214
|
+
if @buffer.buffer_chunk_limit > limit
|
215
|
+
$log.warn ":buffer_chunk_limit(#{@buffer.buffer_chunk_limit}) is large. Reset :buffer_chunk_limit with #{limit}"
|
216
|
+
limit
|
217
|
+
else
|
218
|
+
@buffer.buffer_chunk_limit
|
219
|
+
end
|
221
220
|
end
|
222
|
-
end
|
223
221
|
|
224
|
-
|
225
|
-
|
226
|
-
db.command('buildInfo' => 1)['version']
|
227
|
-
end
|
228
|
-
end
|
222
|
+
def mongod_version
|
223
|
+
version = nil
|
229
224
|
|
225
|
+
begin
|
226
|
+
version = get_connection.command('buildInfo' => 1)['version']
|
227
|
+
rescue Mongo::OperationFailure
|
228
|
+
# fallback for buggy mongod version support
|
229
|
+
version = authenticate(Mongo::MongoClient.new(@host, @port, @connection_options).db('admin')).command('buildInfo' => 1)['version']
|
230
|
+
end
|
230
231
|
|
232
|
+
version
|
233
|
+
end
|
234
|
+
end
|
231
235
|
end
|
@@ -1,73 +1,69 @@
|
|
1
1
|
require 'fluent/plugin/out_mongo'
|
2
2
|
|
3
3
|
module Fluent
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
4
|
+
class MongoOutputReplset < MongoOutput
|
5
|
+
Plugin.register_output('mongo_replset', self)
|
6
|
+
|
7
|
+
config_param :nodes, :string
|
8
|
+
config_param :name, :string, :default => nil
|
9
|
+
config_param :read, :string, :default => nil
|
10
|
+
config_param :refresh_mode, :string, :default => nil
|
11
|
+
config_param :refresh_interval, :integer, :default => nil
|
12
|
+
config_param :num_retries, :integer, :default => 60
|
13
|
+
|
14
|
+
# disable single node configuration
|
15
|
+
config_param :host, :string, :default => nil
|
16
|
+
config_param :port, :integer, :default => nil
|
17
|
+
|
18
|
+
def configure(conf)
|
19
|
+
super
|
20
|
+
|
21
|
+
@nodes = parse_nodes(conf['nodes'])
|
22
|
+
if name = conf['name']
|
23
|
+
@connection_options[:name] = conf['name']
|
24
|
+
end
|
25
|
+
if read = conf['read']
|
26
|
+
@connection_options[:read] = read.to_sym
|
27
|
+
end
|
28
|
+
if refresh_mode = conf['refresh_mode']
|
29
|
+
@connection_options[:refresh_mode] = refresh_mode.to_sym
|
30
|
+
end
|
31
|
+
if refresh_interval = conf['refresh_interval']
|
32
|
+
@connection_options[:refresh_interval] = refresh_interval
|
33
|
+
end
|
34
|
+
|
35
|
+
$log.debug "Setup replica set configuration: nodes = #{conf['nodes']}"
|
32
36
|
end
|
33
|
-
if refresh_interval = conf['refresh_interval']
|
34
|
-
@connection_options[:refresh_interval] = refresh_interval
|
35
|
-
end
|
36
|
-
|
37
|
-
$log.debug "Setup replica set configuration: nodes = #{conf['nodes']}"
|
38
|
-
end
|
39
37
|
|
40
|
-
|
38
|
+
private
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
def operate(collection, records)
|
41
|
+
rescue_connection_failure do
|
42
|
+
super(collection, records)
|
43
|
+
end
|
45
44
|
end
|
46
|
-
end
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
def get_connection
|
53
|
-
db = Mongo::MongoReplicaSetClient.new(@nodes, @connection_options).db(@database)
|
54
|
-
authenticate(db)
|
55
|
-
end
|
46
|
+
def parse_nodes(nodes)
|
47
|
+
nodes.split(',')
|
48
|
+
end
|
56
49
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
rescue Mongo::ConnectionFailure => e
|
62
|
-
retries += 1
|
63
|
-
raise e if retries > @num_retries
|
50
|
+
def get_connection
|
51
|
+
db = Mongo::MongoReplicaSetClient.new(@nodes, @connection_options).db(@database)
|
52
|
+
authenticate(db)
|
53
|
+
end
|
64
54
|
|
65
|
-
|
66
|
-
|
67
|
-
|
55
|
+
def rescue_connection_failure
|
56
|
+
retries = 0
|
57
|
+
begin
|
58
|
+
yield
|
59
|
+
rescue Mongo::ConnectionFailure => e
|
60
|
+
retries += 1
|
61
|
+
raise e if retries > @num_retries
|
62
|
+
|
63
|
+
$log.warn "Failed to connect to Replica Set. Try to retry: retry number = #{retries}"
|
64
|
+
sleep 0.5
|
65
|
+
retry
|
66
|
+
end
|
68
67
|
end
|
69
68
|
end
|
70
69
|
end
|
71
|
-
|
72
|
-
|
73
|
-
end
|
@@ -1,24 +1,20 @@
|
|
1
1
|
require 'fluent/plugin/out_mongo'
|
2
2
|
|
3
3
|
module Fluent
|
4
|
+
class MongoOutputTagCollection < MongoOutput
|
5
|
+
Plugin.register_output('mongo_tag_collection', self)
|
4
6
|
|
7
|
+
config_param :collection, :string, :default => 'untagged'
|
5
8
|
|
6
|
-
|
7
|
-
|
9
|
+
def configure(conf)
|
10
|
+
super
|
8
11
|
|
9
|
-
|
12
|
+
@tag_mapped = true
|
13
|
+
if remove_prefix_collection = conf['remove_prefix_collection']
|
14
|
+
@remove_tag_prefix = Regexp.new('^' + Regexp.escape(remove_prefix_collection))
|
15
|
+
end
|
10
16
|
|
11
|
-
|
12
|
-
super
|
13
|
-
|
14
|
-
@tag_mapped = true
|
15
|
-
if remove_prefix_collection = conf['remove_prefix_collection']
|
16
|
-
@remove_tag_prefix = Regexp.new('^' + Regexp.escape(remove_prefix_collection))
|
17
|
+
$log.warn "'mongo_tag_collection' deprecated. Please use 'mongo' type with 'tag_mapped' parameter"
|
17
18
|
end
|
18
|
-
|
19
|
-
$log.warn "'mongo_tag_collection' deprecated. Please use 'mongo' type with 'tag_mapped' parameter"
|
20
19
|
end
|
21
20
|
end
|
22
|
-
|
23
|
-
|
24
|
-
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
5
|
-
prerelease:
|
4
|
+
version: 0.7.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Masahiro Nakagawa
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-07-31 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: fluentd
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: mongo
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,49 +41,43 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rake
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 0.9.2
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 0.9.2
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: simplecov
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: 0.5.4
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: 0.5.4
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: rr
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: 1.0.0
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - '>='
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: 1.0.0
|
94
83
|
description: MongoDB plugin for Fluent event collector
|
@@ -112,7 +101,6 @@ files:
|
|
112
101
|
- lib/fluent/plugin/in_mongo_tail.rb
|
113
102
|
- lib/fluent/plugin/mongo_util.rb
|
114
103
|
- lib/fluent/plugin/out_mongo.rb
|
115
|
-
- lib/fluent/plugin/out_mongo_backup.rb
|
116
104
|
- lib/fluent/plugin/out_mongo_replset.rb
|
117
105
|
- lib/fluent/plugin/out_mongo_tag_collection.rb
|
118
106
|
- test/plugin/in_mongo_tail.rb
|
@@ -124,33 +112,26 @@ files:
|
|
124
112
|
- test/tools/rs_test_helper.rb
|
125
113
|
homepage: https://github.com/fluent/fluent-plugin-mongo
|
126
114
|
licenses: []
|
115
|
+
metadata: {}
|
127
116
|
post_install_message:
|
128
117
|
rdoc_options: []
|
129
118
|
require_paths:
|
130
119
|
- lib
|
131
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
-
none: false
|
133
121
|
requirements:
|
134
|
-
- -
|
122
|
+
- - '>='
|
135
123
|
- !ruby/object:Gem::Version
|
136
124
|
version: '0'
|
137
|
-
segments:
|
138
|
-
- 0
|
139
|
-
hash: -2812294622738366735
|
140
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
-
none: false
|
142
126
|
requirements:
|
143
|
-
- -
|
127
|
+
- - '>='
|
144
128
|
- !ruby/object:Gem::Version
|
145
129
|
version: '0'
|
146
|
-
segments:
|
147
|
-
- 0
|
148
|
-
hash: -2812294622738366735
|
149
130
|
requirements: []
|
150
131
|
rubyforge_project:
|
151
|
-
rubygems_version:
|
132
|
+
rubygems_version: 2.0.2
|
152
133
|
signing_key:
|
153
|
-
specification_version:
|
134
|
+
specification_version: 4
|
154
135
|
summary: MongoDB plugin for Fluent event collector
|
155
136
|
test_files:
|
156
137
|
- test/plugin/in_mongo_tail.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'fluent/plugin/out_copy'
|
2
|
-
require 'fluent/plugin/out_mongo'
|
3
|
-
|
4
|
-
|
5
|
-
module Fluent
|
6
|
-
|
7
|
-
|
8
|
-
class MongoBackupOutput < CopyOutput
|
9
|
-
Fluent::Plugin.register_output('mongo_backup', self)
|
10
|
-
|
11
|
-
class MongoOutputForBackup < MongoOutput
|
12
|
-
config_param :database, :string, :default => 'fluent'
|
13
|
-
config_param :collection, :string, :default => 'out_mongo_backup'
|
14
|
-
|
15
|
-
# TODO: optimize
|
16
|
-
end
|
17
|
-
|
18
|
-
def configure(conf)
|
19
|
-
super
|
20
|
-
|
21
|
-
backup = MongoOutputForBackup.new
|
22
|
-
backup.configure(conf.merge({'capped' => true}))
|
23
|
-
@outputs.unshift(backup)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
end
|