fluent-plugin-out-solr 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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