fluent-plugin-out-solr 0.0.3 → 0.0.4

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: f134d6f7dcc1c67533c8bf19deb402cab474d64c
4
- data.tar.gz: 8433e0d6e1b0bf02dabdf70f9ed592e1c622d6ec
3
+ metadata.gz: 9fba370cfa9aa095c4d62a31298fb5986d7e82c3
4
+ data.tar.gz: bc3e47a0617809a5ccee18e9811eb3832eef63f5
5
5
  SHA512:
6
- metadata.gz: 84430230e21373715cb2b956021119992b488290f65584208850bc613bc4d67f689f1fe44eb357af6579265edc376aec10ada999380cc1f63a675475720285db
7
- data.tar.gz: 5097d3937e3966989c3dea2ef74706ff9174b711a1a96727bab1a51b72143d9d9cfa29e4236d445e6b20ffba8a813a9d2aed96a1e003c32390af60b20890bbba
6
+ metadata.gz: 58b5f2a164b2851f917843e29b70db8fc91d160c887441bb66969011a64727da40b93809d47c8620d32153fbb319a9b807cff48b0affbe3fc05172fd25576e66
7
+ data.tar.gz: 982239392497f4e9a88e9bfdc5f93ef404fe58c4b7d7e215220c3ba78996e4f02dfcb6f891d3e5daaf10bcfa174d9d159903ccca89a361d9d18d8a721bef2157
data/README.md CHANGED
@@ -30,15 +30,18 @@ Notice: no relationship with [btigit/fluent-plugin-solr](https://github.com/btig
30
30
  include_tag_key true
31
31
  tag_key tag
32
32
  time_field timestamp
33
- use_utc false
33
+ utc # if you do not want to use localtime
34
+
34
35
  flush_interval 3s
35
36
  </match>
36
37
  ```
37
38
 
38
- #### core rotation by date
39
+ #### time sliced by date
39
40
 
40
41
  You should create cores in advance.
41
42
 
43
+ See: [Time Sliced Plugin Overview - Buffer Plugin Overview | Fluentd](http://docs.fluentd.org/articles/buffer-plugin-overview#time-sliced-plugin-overview)
44
+
42
45
  ```
43
46
  <source>
44
47
  type tail
@@ -48,24 +51,35 @@ You should create cores in advance.
48
51
  </source>
49
52
 
50
53
  <match apache.*>
51
- type solr
54
+ type solr_time_sliced
52
55
  host localhost
53
56
  port 8983
54
- use_core_rotation true
55
- core_prefix apache
57
+ core log-%Y%m%d
56
58
  include_tag_key true
57
59
  tag_key tag
58
60
  time_field timestamp
59
- use_utc false
61
+ utc # if you do not want to use localtime
62
+
60
63
  flush_interval 3s
61
64
  </match>
62
65
  ```
63
66
 
64
67
  ### solrconfig.xml snippet
65
68
 
66
- See: [UniqueKey - Solr Wiki](https://wiki.apache.org/solr/UniqueKey)
69
+ * See: [UniqueKey - Solr Wiki](https://wiki.apache.org/solr/UniqueKey)
70
+ * fluent-plugin-out-solr doesn't commit. use autoSoftCommit and autoCommit.
71
+
67
72
 
68
73
  ```xml
74
+ <autoCommit>
75
+ <maxTime>${solr.autoCommit.maxTime:15000}</maxTime>
76
+ <openSearcher>false</openSearcher>
77
+ </autoCommit>
78
+
79
+ <autoSoftCommit>
80
+ <maxTime>${solr.autoSoftCommit.maxTime:10}</maxTime>
81
+ </autoSoftCommit>
82
+
69
83
  <requestHandler name="/update" class="solr.UpdateRequestHandler">
70
84
  <lst name="defaults">
71
85
  <str name="update.chain">uuid</str>
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'fluent-plugin-out-solr'
6
- s.version = '0.0.3'
6
+ s.version = '0.0.4'
7
7
  s.authors = ['diogo', 'pitr', 'haruyama']
8
8
  s.email = ['team@uken.com', 'haruyama@unixuser.org']
9
9
  s.description = %q{Solr output plugin for Fluent event collector}
@@ -20,5 +20,4 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_development_dependency 'rake'
22
22
  s.add_development_dependency 'webmock'
23
- s.add_development_dependency 'timecop'
24
23
  end
@@ -1,27 +1,35 @@
1
1
  # encoding: UTF-8
2
- require 'net/http'
3
- require 'uri'
4
2
 
5
3
  # Solr output plugin for Fluent
6
4
  class Fluent::SolrOutput < Fluent::BufferedOutput
7
5
  Fluent::Plugin.register_output('solr', self)
8
6
 
7
+ require 'fluent/plugin/solr_util'
8
+ include SolrUtil
9
+
9
10
  config_param :host, :string, default: 'localhost'
10
11
  config_param :port, :integer, default: 8983
11
12
  config_param :core, :string, default: 'collection1'
12
- config_param :use_core_rotation, :bool, default: false
13
- config_param :core_prefix, :string, default: 'core'
14
13
  config_param :time_field, :string, default: 'timestamp'
15
- config_param :use_utc, :bool, default: false
16
14
 
17
15
  include Fluent::SetTagKeyMixin
18
16
  config_set_default :include_tag_key, false
19
17
 
18
+ attr_accessor :localtime
20
19
  def initialize
20
+ require 'net/http'
21
+ require 'uri'
22
+ require 'time'
21
23
  super
24
+ @localtime = true
22
25
  end
23
26
 
24
27
  def configure(conf)
28
+ if conf['utc']
29
+ @localtime = false
30
+ elsif conf['localtime']
31
+ @localtime = true
32
+ end
25
33
  super
26
34
  end
27
35
 
@@ -38,25 +46,6 @@ class Fluent::SolrOutput < Fluent::BufferedOutput
38
46
  end
39
47
 
40
48
  def write(chunk)
41
- bulk_messages = Hash.new { |h, k| h[k] = [] }
42
-
43
- chunk.msgpack_each do |tag, unixtime, record|
44
- time = Time.at(unixtime)
45
- time = time.utc if @use_utc
46
- record.merge!(@time_field => time.strftime('%FT%TZ'))
47
- record.merge!(@tag_key => tag) if @include_tag_key
48
- if @use_core_rotation
49
- bulk_messages[@core_prefix + '-' + time.strftime('%F')] << record
50
- else
51
- bulk_messages[@core] << record
52
- end
53
- end
54
-
55
- http = Net::HTTP.new(@host, @port.to_i)
56
- bulk_messages.each do |corename, messages|
57
- request = Net::HTTP::Post.new('/solr/' + URI.escape(corename) + '/update', 'content-type' => 'application/json; charset=utf-8')
58
- request.body = Yajl::Encoder.encode(messages)
59
- http.request(request).value
60
- end
49
+ update_core(chunk, @core)
61
50
  end
62
51
  end
@@ -0,0 +1,63 @@
1
+ # encoding: UTF-8
2
+
3
+ # Solr output plugin for Fluent
4
+ class Fluent::SolrTimeSlicedOutput < Fluent::TimeSlicedOutput
5
+ Fluent::Plugin.register_output('solr_time_sliced', self)
6
+
7
+ require 'fluent/plugin/solr_util'
8
+ include SolrUtil
9
+
10
+ config_set_default :buffer_type, 'memory'
11
+ config_set_default :time_slice_format, '%Y%m%d'
12
+
13
+ config_param :host, :string, default: 'localhost'
14
+ config_param :port, :integer, default: 8983
15
+ config_param :core, :string, default: 'log-%Y%m%d'
16
+ config_param :time_field, :string, default: 'timestamp'
17
+
18
+ include Fluent::SetTagKeyMixin
19
+ config_set_default :include_tag_key, false
20
+
21
+ attr_accessor :localtime
22
+
23
+ def initialize
24
+ require 'net/http'
25
+ require 'uri'
26
+ require 'time'
27
+ super
28
+ @localtime = true
29
+ end
30
+
31
+ def configure(conf)
32
+ if conf['core']
33
+ if conf['core'].index('%S')
34
+ conf['time_slice_format'] = '%Y%m%d%H%M%S'
35
+ elsif conf['core'].index('%M')
36
+ conf['time_slice_format'] = '%Y%m%d%H%M'
37
+ elsif conf['core'].index('%H')
38
+ conf['time_slice_format'] = '%Y%m%d%H'
39
+ end
40
+ end
41
+ super
42
+ end
43
+
44
+ def start
45
+ super
46
+ end
47
+
48
+ def format(tag, time, record)
49
+ [tag, time, record].to_msgpack
50
+ end
51
+
52
+ def shutdown
53
+ super
54
+ end
55
+
56
+ def core_format(chunk_key)
57
+ Time.strptime(chunk_key, @time_slice_format).strftime(@core)
58
+ end
59
+
60
+ def write(chunk)
61
+ update_core(chunk, core_format(chunk.key))
62
+ end
63
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+
3
+ # Solr utility
4
+ module SolrUtil
5
+ def update_core(chunk, core)
6
+ documents = []
7
+
8
+ chunk.msgpack_each do |tag, unixtime, record|
9
+ time = Time.at(unixtime)
10
+ time = time.utc unless @localtime
11
+ record.merge!(@time_field => time.strftime('%FT%TZ'))
12
+ record.merge!(@tag_key => tag) if @include_tag_key
13
+ documents << record
14
+ end
15
+
16
+ http = Net::HTTP.new(@host, @port.to_i)
17
+ request = Net::HTTP::Post.new('/solr/' + URI.escape(core) + '/update', 'content-type' => 'application/json; charset=utf-8')
18
+ request.body = Yajl::Encoder.encode(documents)
19
+ http.request(request).value
20
+ end
21
+ end
@@ -4,7 +4,6 @@ require 'fluent/test'
4
4
  require 'fluent/plugin/out_solr'
5
5
 
6
6
  require 'webmock/test_unit'
7
- require 'timecop'
8
7
 
9
8
  require 'helper'
10
9
 
@@ -16,7 +15,6 @@ WebMock.disable_net_connect!
16
15
  # Solr output test
17
16
  class SolrOutput < Test::Unit::TestCase
18
17
  attr_accessor :index_cmds, :content_type
19
- attr_accessor :index_cmds2
20
18
 
21
19
  def setup
22
20
  Fluent::Test.setup
@@ -38,21 +36,13 @@ class SolrOutput < Test::Unit::TestCase
38
36
  end
39
37
  end
40
38
 
41
- def stub_solr2(url = 'http://localhost:8983/solr/collection1/update')
42
- stub_request(:post, url).with do |req|
43
- @index_cmds2 = JSON.parse(req.body)
44
- end
45
- end
46
-
47
39
  def stub_solr_unavailable(url = 'http://localhost:8983/solr/collection1/update')
48
40
  stub_request(:post, url).to_return(status: [503, 'Service Unavailable'])
49
41
  end
50
42
 
51
43
  def test_writes_to_default_index
52
44
  stub_solr
53
- Timecop.freeze(Time.local(2013, 12, 20, 19, 0, 0)) do
54
- driver.emit(sample_record)
55
- end
45
+ driver.emit(sample_record, Time.local(2013, 12, 20, 19, 0, 0).to_i)
56
46
  driver.run
57
47
  assert_equal(26, @index_cmds[0]['age'])
58
48
  assert_equal('42', @index_cmds[0]['request_id'])
@@ -116,32 +106,16 @@ class SolrOutput < Test::Unit::TestCase
116
106
  assert_equal(@index_cmds[0]['tag'], 'mytag')
117
107
  end
118
108
 
119
- def test_use_utc
120
- driver.configure("use_utc true\n")
109
+ def test_utc
110
+ driver.configure("utc\n")
121
111
  stub_solr
122
- Timecop.freeze(Time.local(2013, 12, 20, 19, 0, 0)) do
123
- driver.emit(sample_record)
124
- end
112
+ ENV['TZ'] = 'Japan'
113
+ driver.emit(sample_record, Time.local(2013, 12, 20, 19, 0, 0).to_i)
114
+ ENV['TZ'] = nil
125
115
  driver.run
126
116
  assert_equal('2013-12-20T10:00:00Z', @index_cmds[0]['timestamp'])
127
117
  end
128
118
 
129
- def test_use_core_rotation
130
- driver.configure("use_core_rotation true\n")
131
- driver.configure("core_prefix log\n")
132
- stub_solr('http://localhost:8983/solr/log-2013-12-20/update')
133
- stub_solr2('http://localhost:8983/solr/log-2013-12-21/update')
134
- Timecop.freeze(Time.local(2013, 12, 20, 19, 0, 0)) do
135
- driver.emit(sample_record)
136
- end
137
- Timecop.freeze(Time.local(2013, 12, 21, 19, 0, 0)) do
138
- driver.emit(sample_record)
139
- end
140
- driver.run
141
- assert_equal(1, @index_cmds.count)
142
- assert_equal(1, @index_cmds2.count)
143
- end
144
-
145
119
  def test_request_error
146
120
  stub_solr_unavailable
147
121
  driver.emit(sample_record)
@@ -0,0 +1,168 @@
1
+ require 'test/unit'
2
+
3
+ require 'fluent/test'
4
+ require 'fluent/plugin/out_solr_time_sliced'
5
+
6
+ require 'webmock/test_unit'
7
+
8
+ require 'helper'
9
+
10
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
11
+ $LOAD_PATH.push File.dirname(__FILE__)
12
+
13
+ WebMock.disable_net_connect!
14
+
15
+ # SolrTimeSlicedOutput test
16
+ class SolrTimeSlicedOutputTest < Test::Unit::TestCase
17
+ attr_accessor :index_cmds, :content_type
18
+ attr_accessor :index_cmds2
19
+
20
+ def setup
21
+ Fluent::Test.setup
22
+ @driver = nil
23
+ end
24
+
25
+ def driver(tag = 'test', conf = '')
26
+ @driver ||= Fluent::Test::TimeSlicedOutputTestDriver.new(Fluent::SolrTimeSlicedOutput, tag).configure(conf)
27
+ end
28
+
29
+ def sample_record
30
+ { 'age' => 26, 'request_id' => '42' }
31
+ end
32
+
33
+ def time
34
+ Time.local(2013, 12, 21, 17, 30, 0).to_i
35
+ end
36
+
37
+ def time2
38
+ Time.local(2013, 12, 22, 17, 30, 0).to_i
39
+ end
40
+
41
+ def stub_solr(url = 'http://localhost:8983/solr/log-20131221/update')
42
+ stub_request(:post, url).with do |req|
43
+ @content_type = req.headers['Content-Type']
44
+ @index_cmds = JSON.parse(req.body)
45
+ end
46
+ end
47
+
48
+ def stub_solr2(url = 'http://localhost:8983/solr/log-20131222/update')
49
+ stub_request(:post, url).with do |req|
50
+ @content_type2 = req.headers['Content-Type']
51
+ @index_cmds2 = JSON.parse(req.body)
52
+ end
53
+ end
54
+
55
+ def stub_solr_unavailable(url = 'http://localhost:8983/solr/log-20131221/update')
56
+ stub_request(:post, url).to_return(status: [503, 'Service Unavailable'])
57
+ end
58
+
59
+ def test_writes_to_default_index
60
+ stub_solr
61
+ driver.emit(sample_record, time)
62
+ driver.run
63
+ assert_equal(26, @index_cmds[0]['age'])
64
+ assert_equal('42', @index_cmds[0]['request_id'])
65
+ assert_equal('2013-12-21T17:30:00Z', @index_cmds[0]['timestamp'])
66
+ end
67
+
68
+ def test_wrties_with_proper_content_type
69
+ stub_solr
70
+ driver.emit(sample_record)
71
+ driver.run
72
+ assert_equal('application/json; charset=utf-8', @content_type)
73
+ end
74
+
75
+ def test_writes_to_speficied_core
76
+ driver.configure("core log-%Y%m%d%H\n")
77
+ solr_request = stub_solr('http://localhost:8983/solr/log-2013122117/update')
78
+ driver.emit(sample_record, time)
79
+ driver.run
80
+ assert_requested(solr_request)
81
+ end
82
+
83
+ def test_writes_to_speficied_core2
84
+ driver.configure("core log2-%Y%m%d%H%M\n")
85
+ solr_request = stub_solr('http://localhost:8983/solr/log2-201312211730/update')
86
+ driver.emit(sample_record, time)
87
+ driver.run
88
+ assert_requested(solr_request)
89
+ end
90
+
91
+ def test_writes_to_speficied_core3
92
+ driver.configure("core log3-%Y%m%d%H%M%S\n")
93
+ solr_request = stub_solr('http://localhost:8983/solr/log3-20131221173000/update')
94
+ driver.emit(sample_record, time)
95
+ driver.run
96
+ assert_requested(solr_request)
97
+ end
98
+
99
+ def test_writes_to_speficied_host
100
+ driver.configure("host 192.168.33.50\n")
101
+ solr_request = stub_solr('http://192.168.33.50:8983/solr/log-20131221/update')
102
+ driver.emit(sample_record, time)
103
+ driver.run
104
+ assert_requested(solr_request)
105
+ end
106
+
107
+ def test_writes_to_speficied_port
108
+ driver.configure("port 9201\n")
109
+ solr_request = stub_solr('http://localhost:9201/solr/log-20131221/update')
110
+ driver.emit(sample_record, time)
111
+ driver.run
112
+ assert_requested(solr_request)
113
+ end
114
+
115
+ def test_emit_multi_records
116
+ stub_solr
117
+ driver.emit(sample_record, time)
118
+ driver.emit(sample_record.merge('age' => 27), time)
119
+ driver.run
120
+ assert_equal(2, @index_cmds.count)
121
+ assert_equal(26, @index_cmds[0]['age'])
122
+ assert_equal(27, @index_cmds[1]['age'])
123
+ end
124
+
125
+ def test_doesnt_add_tag_key_by_default
126
+ stub_solr
127
+ driver.emit(sample_record)
128
+ driver.run
129
+ assert_nil(@index_cmds[0]['tag'])
130
+ end
131
+
132
+ def test_adds_tag_key_when_configured
133
+ driver('mytag').configure("include_tag_key true\n")
134
+ stub_solr
135
+ driver.emit(sample_record, time)
136
+ driver.run
137
+ assert(@index_cmds[0].key?('tag'))
138
+ assert_equal(@index_cmds[0]['tag'], 'mytag')
139
+ end
140
+
141
+ def test_utc
142
+ driver.configure("utc\n")
143
+ stub_solr
144
+ ENV['TZ'] = 'Japan'
145
+ driver.emit(sample_record, Time.local(2013, 12, 22, 7, 30, 0).to_i)
146
+ ENV['TZ'] = nil
147
+ driver.run
148
+ assert_equal('2013-12-21T22:30:00Z', @index_cmds[0]['timestamp'])
149
+ end
150
+
151
+ def test_emit_records_on_different_days
152
+ stub_solr
153
+ stub_solr2
154
+ driver.emit(sample_record, time)
155
+ driver.emit(sample_record, time2)
156
+ driver.run
157
+ assert_equal(1, @index_cmds.count)
158
+ assert_equal(1, @index_cmds2.count)
159
+ end
160
+
161
+ def test_request_error
162
+ stub_solr_unavailable
163
+ driver.emit(sample_record, time)
164
+ assert_raise(Net::HTTPFatalError) do
165
+ driver.run
166
+ end
167
+ end
168
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-out-solr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - diogo
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-12-20 00:00:00.000000000 Z
13
+ date: 2013-12-21 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: fluentd
@@ -54,20 +54,6 @@ dependencies:
54
54
  - - '>='
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
- - !ruby/object:Gem::Dependency
58
- name: timecop
59
- requirement: !ruby/object:Gem::Requirement
60
- requirements:
61
- - - '>='
62
- - !ruby/object:Gem::Version
63
- version: '0'
64
- type: :development
65
- prerelease: false
66
- version_requirements: !ruby/object:Gem::Requirement
67
- requirements:
68
- - - '>='
69
- - !ruby/object:Gem::Version
70
- version: '0'
71
57
  description: Solr output plugin for Fluent event collector
72
58
  email:
73
59
  - team@uken.com
@@ -83,9 +69,12 @@ files:
83
69
  - Rakefile
84
70
  - fluent-plugin-out-solr.gemspec
85
71
  - lib/fluent/plugin/out_solr.rb
72
+ - lib/fluent/plugin/out_solr_time_sliced.rb
73
+ - lib/fluent/plugin/solr_util.rb
86
74
  - test/helper.rb
87
75
  - test/plugin/.rubocop.yml
88
76
  - test/plugin/test_out_solr.rb
77
+ - test/plugin/test_out_solr_time_sliced.rb
89
78
  homepage: https://github.com/haruyama/fluent-plugin-out-solr
90
79
  licenses:
91
80
  - MIT
@@ -114,3 +103,4 @@ test_files:
114
103
  - test/helper.rb
115
104
  - test/plugin/.rubocop.yml
116
105
  - test/plugin/test_out_solr.rb
106
+ - test/plugin/test_out_solr_time_sliced.rb