fluent-plugin-mongo 0.7.0 → 0.7.1
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 +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
|