logstash-output-qingstor 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,64 +1,69 @@
1
1
  # encoding: utf-8
2
- require "qingstor/sdk"
3
- require "concurrent"
4
- require "digest/md5"
5
- require "base64"
2
+
3
+ require 'logstash/outputs/qingstor'
4
+ require 'qingstor/sdk'
5
+ require 'concurrent'
6
+ require 'digest/md5'
7
+ require 'base64'
8
+
6
9
  module LogStash
7
10
  module Outputs
8
11
  class Qingstor
9
- class Uploader
12
+ class Uploader
10
13
  TIME_BEFORE_RETRYING_SECONDS = 1
11
- DEFAULT_THREADPOOL = Concurrent::ThreadPoolExecutor.new({ :min_thread => 1,
12
- :max_thread => 8,
13
- :max_queue => 1,
14
- :fallback_policy => :caller_runs
15
- })
16
- attr_reader :bucket, :upload_options, :logger
14
+ DEFAULT_THREADPOOL = Concurrent::ThreadPoolExecutor.new(
15
+ :min_thread => 1,
16
+ :max_thread => 8,
17
+ :max_queue => 1,
18
+ :fallback_policy => :caller_runs
19
+ )
20
+
21
+ attr_reader :bucket, :upload_options, :logger
17
22
 
18
23
  def initialize(bucket, logger, threadpool = DEFAULT_THREADPOOL)
19
24
  @bucket = bucket
20
25
  @logger = logger
21
26
  @workers_pool = threadpool
22
- end
27
+ end
23
28
 
24
29
  def upload_async(file, options = {})
25
30
  @workers_pool.post do
26
31
  upload(file, options)
27
- end
28
- end
32
+ end
33
+ end
29
34
 
30
35
  def upload(file, options = {})
31
36
  upload_options = options.fetch(:upload_options, {})
32
37
 
33
38
  file_md5 = Digest::MD5.file(file.path).to_s
34
-
39
+
35
40
  upload_headers = {
36
- "content_md5" => file_md5,
37
- "body" => ::File.open(file.path)
41
+ 'content_md5' => file_md5,
42
+ 'body' => ::File.open(file.path)
38
43
  }
39
44
 
40
- if !upload_options[:server_side_encryption_algorithm].nil?
41
- base64_key = Base64.strict_encode64 upload_options[:customer_key]
42
- key_md5 = Digest::MD5.hexdigest upload_options[:customer_key]
43
- base64_key_md5 = Base64.strict_encode64 key_md5
44
- upload_headers.merge!({
45
- "x_qs_encryption_customer_algorithm" => upload_options[:server_side_encryption_algorithm],
46
- "x_qs_encryption_customer_key" => base64_key,
47
- "x_qs_encryption_customer_key_md5" => base64_key_md5,
48
- })
49
- end
50
- @logger.debug("uploading file", :file => file.key)
45
+ unless upload_options[:server_side_encryption_algorithm].nil?
46
+ base64_key = Base64.strict_encode64(upload_options[:customer_key])
47
+ key_md5 = Digest::MD5.hexdigest(upload_options[:customer_key])
48
+ base64_key_md5 = Base64.strict_encode64(key_md5)
49
+ upload_headers.merge!(
50
+ 'x_qs_encryption_customer_algorithm' =>
51
+ upload_options[:server_side_encryption_algorithm],
52
+ 'x_qs_encryption_customer_key' => base64_key,
53
+ 'x_qs_encryption_customer_key_md5' => base64_key_md5
54
+ )
55
+ end
56
+ @logger.debug('uploading file', :file => file.key)
51
57
  bucket.put_object(file.key, upload_headers)
52
58
 
53
59
  options[:on_complete].call(file) unless options[:on_complete].nil?
54
- end
60
+ end
55
61
 
56
- def stop
62
+ def stop
57
63
  @workers_pool.shutdown
58
64
  @workers_pool.wait_for_termination(nil)
59
- end
60
- end
61
- end
62
- end
63
- end
64
-
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,37 +1,41 @@
1
1
  # encoding: utf-8
2
- require "logstash-core"
3
- require "logstash/outputs/base"
4
- require "logstash/namespace"
5
- require "tmpdir"
6
- require "qingstor/sdk"
7
- require "concurrent"
2
+
3
+ require 'logstash-core'
4
+ require 'logstash/outputs/base'
5
+ require 'logstash/namespace'
6
+ require 'tmpdir'
7
+ require 'qingstor/sdk'
8
+ require 'concurrent'
8
9
 
9
10
  class LogStash::Outputs::Qingstor < LogStash::Outputs::Base
10
- require "logstash/outputs/qingstor/temporary_file"
11
- require "logstash/outputs/qingstor/temporary_file_factory"
12
- require "logstash/outputs/qingstor/file_repository"
13
- require "logstash/outputs/qingstor/rotation_policy"
14
- require "logstash/outputs/qingstor/uploader"
15
- require "logstash/outputs/qingstor/qingstor_validator"
11
+ require 'logstash/outputs/qingstor/temporary_file'
12
+ require 'logstash/outputs/qingstor/temporary_file_factory'
13
+ require 'logstash/outputs/qingstor/file_repository'
14
+ require 'logstash/outputs/qingstor/rotation_policy'
15
+ require 'logstash/outputs/qingstor/uploader'
16
+ require 'logstash/outputs/qingstor/qingstor_validator'
16
17
 
17
18
  PERIODIC_CHECK_INTERVAL_IN_SECONDS = 15
18
- CRASH_RECOVERY_THREADPOOL = Concurrent::ThreadPoolExecutor.new({
19
- :min_threads => 1,
20
- :max_threads => 2,
21
- :fallback_policy => :caller_runs
22
- })
23
- config_name "qingstor"
24
-
25
- # When configured as :single a single instance of the Output will be shared among the
26
- # pipeline worker threads. Access to the `#multi_receive/#multi_receive_encoded/#receive` method will be synchronized
27
- # i.e. only one thread will be active at a time making threadsafety much simpler.
19
+ CRASH_RECOVERY_THREADPOOL = Concurrent::ThreadPoolExecutor.new(
20
+ :min_threads => 1,
21
+ :max_threads => 2,
22
+ :fallback_policy => :caller_runs
23
+ )
24
+
25
+ config_name 'qingstor'
26
+
27
+ # When configured as :single a single instance of the Output will be shared
28
+ # among the pipeline worker threads. Access to the `#multi_receive/
29
+ # #multi_receive_encoded/#receive` method will be synchronized i.e. only one
30
+ # thread will be active at a time making threadsafety much simpler.
28
31
  #
29
- # You can set this to :shared if your output is threadsafe. This will maximize
30
- # concurrency but you will need to make appropriate uses of mutexes in `#multi_receive/#receive`.
32
+ # You can set this to :shared if your output is threadsafe. This will
33
+ # maximize concurrency but you will need to make appropriate uses of mutexes
34
+ # in `#multi_receive/#receive`.
31
35
  #
32
- # Only the `#multi_receive/#multi_receive_encoded` methods need to actually be threadsafe, the other methods
33
- # will only be executed in a single thread
34
- concurrency :shared
36
+ # Only the `#multi_receive/#multi_receive_encoded` methods need to actually
37
+ # be threadsafe, the other methods will only be executed in a single thread
38
+ concurrency :single
35
39
 
36
40
  # The key id to access your QingStor
37
41
  config :access_key_id, :validate => :string, :required => true
@@ -49,76 +53,85 @@ class LogStash::Outputs::Qingstor < LogStash::Outputs::Base
49
53
  config :bucket, :validate => :string, :required => true
50
54
 
51
55
  # The region of the QingStor bucket
52
- config :region, :validate => ["pek3a", "sh1a"], :default => "pek3a"
56
+ config :region, :validate => %w[pek3a sh1a], :default => 'pek3a'
53
57
 
54
- # The prefix of filenames which will work as directory in qingstor
58
+ # The prefix of filenames which will work as directory in qingstor
55
59
  config :prefix, :validate => :string, :default => ''
56
60
 
57
- # Set the directory where logstash store the tmp files before
58
- # sending it to qingstor, default directory in linux /tmp/logstash2qingstor
59
- config :tmpdir, :validate => :string, :default => File.join(Dir.tmpdir, "logstash2qingstor")
61
+ # Set the directory where logstash store the tmp files before
62
+ # sending it to QingStor, default directory in linux /tmp/logstash2qingstor
63
+ config :tmpdir, :validate => :string,
64
+ :default => File.join(Dir.tmpdir, 'logstash2qingstor')
60
65
 
61
- # Define tags to append to the file on the qingstor bucket
66
+ # Define tags to append to the file on the QingStor bucket
62
67
  config :tags, :validate => :array, :default => []
63
68
 
64
69
  # Specify the content encoding. Supports ("gzip"), defaults to "none"
65
- config :encoding, :validate => ["gzip", "none"], :default => "none"
70
+ config :encoding, :validate => %w[gzip none], :default => 'none'
66
71
 
67
- # Define the strategy to use to decide when we need to rotate the file and push it to S3,
68
- # The default strategy is to check for both size and time, the first one to match will rotate the file.
69
- config :rotation_strategy, :validate => ["size_and_time", "size", "time"], :default => "size_and_time"
72
+ # Define the strategy to use to decide when we need to rotate the file
73
+ # and push it to QingStor.
74
+ # The default strategy is to check for both size and time, the first one to
75
+ # match will rotate the file.
76
+ config :rotation_strategy, :validate => %w[size_and_time size time],
77
+ :default => 'size_and_time'
70
78
 
71
- # Define the size requirement for each file to upload to qingstor. In byte.
79
+ # Define the size requirement for each file to upload to QingStor. In byte.
72
80
  config :file_size, :validate => :number, :default => 1024 * 1024 * 5
73
81
 
74
- # Define the time interval for each file to upload to qingstor. In minutes.
75
- config :file_time, :validate => :number, :default => 15
82
+ # Define the time interval for each file to upload to QingStor. In minutes.
83
+ config :file_time, :validate => :number, :default => 15
76
84
 
77
- # Specify maximum number of workers to use to upload the files to Qingstor
78
- config :upload_workers_count, :validate => :number, :default => (Concurrent.processor_count * 0.5).ceil
85
+ # Specify maximum number of workers to use to upload the files to QingStor
86
+ config :upload_workers_count,
87
+ :validate => :number,
88
+ :default => (Concurrent.processor_count * 0.5).ceil
79
89
 
80
90
  # Number of items we can keep in the local queue before uploading them
81
- config :upload_queue_size, :validate => :number, :default => 2 * (Concurrent.processor_count * 0.25).ceil
91
+ config :upload_queue_size,
92
+ :validate => :number,
93
+ :default => 2 * (Concurrent.processor_count * 0.25).ceil
82
94
 
83
95
  # Specifies what type of encryption to use when SSE is enabled.
84
- config :server_side_encryption_algorithm, :validate => ["AES256", "none"], :default => "none"
96
+ config :server_side_encryption_algorithm, :validate => %w[AES256 none],
97
+ :default => 'none'
85
98
 
86
- # Specifies the encryption customer key that would be used in server side
99
+ # Specifies the encryption customer key that would be used in server side
87
100
  config :customer_key, :validate => :string
88
101
 
89
- # Specifies if set to true, it would upload existing file in targeting folder at the beginning.
90
- config :restore, :validate => :boolean, :default => false
102
+ # Specifies if set to true, it would upload existing file in targeting folder
103
+ # when the plugin is launched
104
+ config :restore, :validate => :boolean, :default => false
91
105
 
92
- public
93
106
  def register
94
107
  QingstorValidator.prefix_valid?(@prefix) unless @prefix.nil?
95
108
 
96
- if !directory_valid?(@tmpdir)
97
- raise LogStash::ConfigurationError, "Logstash must have the permissions to write to the temporary directory: #{@tmpdir}"
109
+ unless directory_valid?(@tmpdir)
110
+ raise LogStash::ConfigurationError,
111
+ "Logstash must have the permissions to write to: #{@tmpdir}"
98
112
  end
99
-
113
+
100
114
  @file_repository = FileRepository.new(@tags, @encoding, @tmpdir)
101
115
 
102
116
  @rotation = RotationPolicy.new(@rotation_strategy, @file_size, @file_time)
103
117
 
104
- executor = Concurrent::ThreadPoolExecutor.new({
118
+ executor = Concurrent::ThreadPoolExecutor.new(
105
119
  :min_threads => 1,
106
120
  :max_threads => @upload_workers_count,
107
121
  :max_queue => @upload_queue_size,
108
- :fallback_policy => :caller_runs
109
- })
122
+ :fallback_policy => :caller_runs
123
+ )
110
124
 
111
- @qs_bucket = get_bucket
125
+ @qs_bucket = getbucket
112
126
  QingstorValidator.bucket_valid?(@qs_bucket)
113
127
 
114
128
  @uploader = Uploader.new(@qs_bucket, @logger, executor)
115
129
 
116
130
  start_periodic_check if @rotation.needs_periodic?
117
131
 
118
- restore_from_crash if @restore
132
+ restore_from_crash if @restore
119
133
  end # def register
120
134
 
121
- public
122
135
  def multi_receive_encoded(events_and_encoded)
123
136
  prefix_written_to = Set.new
124
137
 
@@ -127,18 +140,21 @@ class LogStash::Outputs::Qingstor < LogStash::Outputs::Base
127
140
  prefix_written_to << prefix_key
128
141
 
129
142
  begin
130
- @file_repository.get_file(prefix_key) { |file| file.write(encoded + "\n") }
143
+ @file_repository.get_file(prefix_key) do |f|
144
+ content = encoded.strip + "\n"
145
+ f.write(content)
146
+ end
131
147
  rescue Errno::ENOSPC => e
132
- @logger.error("QingStor: Nospace left in temporary directory", :tmpdir => @tmpdir)
133
- raise e
134
- end
135
- end # end of each method
136
-
137
- # check the file after file writing
138
- # Groups IO calls to optimize fstat checks
148
+ @logger.error('QingStor: Nospace left in temporary directory',
149
+ :tmpdir => @tmpdir)
150
+ raise e
151
+ end
152
+ end # end of each method
153
+
154
+ # check the file after file writing
155
+ # Groups IO calls to optimize fstat checks
139
156
  rotate_if_needed(prefix_written_to)
140
- end # def multi_receive_encoded
141
-
157
+ end # def multi_receive_encoded
142
158
 
143
159
  def rotate_if_needed(prefixs)
144
160
  prefixs.each do |prefix|
@@ -146,103 +162,107 @@ class LogStash::Outputs::Qingstor < LogStash::Outputs::Base
146
162
  tmp_file = factory.current
147
163
 
148
164
  if @rotation.rotate?(tmp_file)
149
- @logger.debug("Rotate file",
165
+ @logger.debug('Rotate file',
150
166
  :strategy => tmp_file.key,
151
167
  :path => tmp_file.path)
152
168
  upload_file(tmp_file)
153
169
  factory.rotate!
154
- end
155
- end
156
- end
170
+ end
171
+ end
172
+ end
157
173
  end # def rotate_if_needed
158
174
 
159
175
  def upload_file(file)
160
- @logger.debug("Add file to uploading queue", :key => file.key)
161
- file.close
162
- @logger.debug("upload options", :upload_options => upload_options)
176
+ @logger.debug('Add file to uploading queue', :key => file.key)
177
+ file.close
178
+ @logger.debug('upload options', :upload_options => upload_options)
163
179
  @uploader.upload_async(file,
164
- :on_complete => method(:clean_temporary_file),
165
- :upload_options => upload_options)
166
- end
180
+ :on_complete => method(:clean_temporary_file),
181
+ :upload_options => upload_options)
182
+ end
167
183
 
168
- def get_bucket
184
+ def getbucket
169
185
  @qs_config = QingStor::SDK::Config.init @access_key_id, @secret_access_key
170
- @qs_config.update({ host: @host, port: @port }) unless @host.nil?
186
+ @qs_config.update(:host => @host, :port => @port) unless @host.nil?
171
187
  @qs_service = QingStor::SDK::Service.new @qs_config
172
188
  @qs_service.bucket @bucket, @region
173
- end
189
+ end
174
190
 
175
- def close
191
+ def close
176
192
  stop_periodic_check if @rotation.needs_periodic?
177
193
 
178
- @logger.debug("uploading current workspace")
194
+ @logger.debug('uploading current workspace')
179
195
  @file_repository.each_files do |file|
180
196
  upload_file(file)
181
- end
197
+ end
182
198
 
183
199
  @file_repository.shutdown
184
200
 
185
- @uploader.stop
201
+ @uploader.stop
186
202
 
187
203
  @crash_uploader.stop if @restore
188
- end
204
+ end
189
205
 
190
206
  def upload_options
191
207
  options = {
192
- :content_encoding => @encoding == "gzip" ? "gzip" : nil
208
+ :content_encoding => @encoding == 'gzip' ? 'gzip' : nil
193
209
  }
194
210
 
195
- if @server_side_encryption_algorithm == "AES256" && !@customer_key.nil?
196
- options.merge!({
197
- :server_side_encryption_algorithm => @server_side_encryption_algorithm,
198
- :customer_key => @customer_key
199
- })
200
- end
201
-
202
- options
203
- end
211
+ if @server_side_encryption_algorithm == 'AES256' && !@customer_key.nil?
212
+ options[:server_side_encryption_algorithm] = @server_side_encryption_algorithm
213
+ options[:customer_key] = @customer_key
214
+ end
215
+
216
+ options
217
+ end
204
218
 
205
219
  def clean_temporary_file(file)
206
- @logger.debug("Removing temporary file", :file => file.path)
220
+ @logger.debug('Removing temporary file', :file => file.path)
207
221
  file.delete!
208
- end
222
+ end
209
223
 
210
224
  def start_periodic_check
211
- @logger.debug("Start periodic rotation check")
225
+ @logger.debug('Start periodic rotation check')
212
226
 
213
- @periodic_check = Concurrent::TimerTask.new(:execution_interval => PERIODIC_CHECK_INTERVAL_IN_SECONDS) do
214
- @logger.debug("Periodic check for stale files")
227
+ @periodic_check = Concurrent::TimerTask.new(
228
+ :execution_interval => PERIODIC_CHECK_INTERVAL_IN_SECONDS
229
+ ) do
230
+ @logger.debug('Periodic check for stale files')
215
231
 
216
232
  rotate_if_needed(@file_repository.keys)
217
233
  end
218
234
 
219
- @periodic_check.execute
220
- end
235
+ @periodic_check.execute
236
+ end
221
237
 
222
- def stop_periodic_check
223
- @periodic_check.shutdown
224
- end
238
+ def stop_periodic_check
239
+ @periodic_check.shutdown
240
+ end
225
241
 
226
242
  def directory_valid?(path)
227
- begin
228
- FileUtils.mkdir_p(path) unless Dir.exist?(path)
229
- ::File.writable?(path)
230
- rescue
231
- false
232
- end
233
- end
243
+ FileUtils.mkdir_p(path) unless Dir.exist?(path)
244
+ ::File.writable?(path)
245
+ rescue
246
+ false
247
+ end
234
248
 
235
- def restore_from_crash
236
- @crash_uploader = Uploader.new(@qs_bucket, @logger, CRASH_RECOVERY_THREADPOOL)
249
+ def restore_from_crash
250
+ @crash_uploader = Uploader.new(@qs_bucket, @logger,
251
+ CRASH_RECOVERY_THREADPOOL)
237
252
 
238
253
  temp_folder_path = Pathname.new(@tmpdir)
239
- Dir.glob(::File.join(@tmpdir, "**/*"))
240
- .select { |file| ::File.file?(file) }
241
- .each do |file|
242
- temp_file = TemporaryFile.create_from_existing_file(file, temp_folder_path)
243
- @logger.debug("Recoving from crash and uploading", :file => temp_file.path)
244
- @crash_uploader.upload_async(temp_file, :on_complete => method(:clean_temporary_file),
245
- :upload_options => upload_options)
246
- end
247
- end
248
- end # class LogStash::Outputs::Qingstor
254
+ Dir.glob(::File.join(@tmpdir, '**/*'))
255
+ .select { |file| ::File.file?(file) }
256
+ .each do |file|
257
+ temp_file = TemporaryFile.create_from_existing_file(file,
258
+ temp_folder_path)
259
+ @logger.debug('Recoving from crash and uploading',
260
+ :file => temp_file.path)
261
+ @crash_uploader.upload_async(
262
+ temp_file,
263
+ :on_complete => method(:clean_temporary_file),
264
+ :upload_options => upload_options
265
+ )
266
+ end
267
+ end
268
+ end # class LogStash::Outputs::Qingstor
@@ -1,28 +1,28 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-qingstor'
3
- s.version = '0.1.3'
3
+ s.version = '0.2.0'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = 'logstash output plugin for qingstor'
6
6
  s.description = 'Collect the outputs of logstash and store into Qingstor'
7
- s.homepage = 'https://github.com/tacinight/logstash-output-qingstor'
7
+ s.homepage = 'https://github.com/yunify/logstash-output-qingstor'
8
8
  s.authors = ['Evan Zhao']
9
9
  s.email = 'tacingiht@gmail.com'
10
10
  s.require_paths = ['lib']
11
11
 
12
12
  # Files
13
- s.files = Dir['lib/**/*','spec/**/*','vendor/**/*','*.gemspec','*.md','CONTRIBUTORS','Gemfile','LICENSE','NOTICE.TXT']
14
- # Tests
13
+ s.files = Dir['lib/**/*', 'spec/**/*', 'vendor/**/*', '*.gemspec', '*.md', 'CONTRIBUTORS', 'Gemfile', 'LICENSE', 'NOTICE.TXT']
14
+ # Tests
15
15
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
16
 
17
17
  # Special flag to let us know this is actually a logstash plugin
18
- s.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
18
+ s.metadata = { 'logstash_plugin' => 'true', 'logstash_group' => 'output' }
19
19
 
20
20
  # Gem dependencies
21
- s.add_runtime_dependency "logstash-core-plugin-api", "~> 2.0"
22
- s.add_runtime_dependency "logstash-codec-plain"
23
- s.add_runtime_dependency "qingstor-sdk", ">=1.9.2"
24
- s.add_runtime_dependency "concurrent-ruby"
25
-
26
- s.add_development_dependency "stud", "~> 0.0.22"
27
- s.add_development_dependency "logstash-devutils"
21
+ s.add_runtime_dependency 'logstash-core-plugin-api', '~> 2.0'
22
+ s.add_runtime_dependency 'logstash-codec-plain'
23
+ s.add_runtime_dependency 'qingstor-sdk', '>=1.9.2'
24
+ s.add_runtime_dependency 'concurrent-ruby'
25
+
26
+ s.add_development_dependency 'stud', '~> 0.0.22'
27
+ s.add_development_dependency 'logstash-devutils'
28
28
  end
@@ -1,26 +1,28 @@
1
- require "logstash/devutils/rspec/spec_helper"
2
- require "logstash/outputs/qingstor/temporary_file"
3
- require "logstash/outputs/qingstor/temporary_file_factory"
4
- require "logstash/outputs/qingstor/file_repository"
5
- require "tmpdir"
6
-
7
- describe LogStash::Outputs::Qingstor::FileRepository do
8
- let(:tags) { ["tag1", "tag2", "tag3"]}
9
- let(:encoding) { "none" }
10
- let(:tmpdir) { File.join(Dir.tmpdir, "lg2qs") }
11
- let(:prefix) { "aprefix" }
1
+ require 'logstash/devutils/rspec/spec_helper'
2
+ require 'logstash/outputs/qingstor/temporary_file'
3
+ require 'logstash/outputs/qingstor/temporary_file_factory'
4
+ require 'logstash/outputs/qingstor/file_repository'
5
+ require 'tmpdir'
12
6
 
7
+ describe LogStash::Outputs::Qingstor::FileRepository do
13
8
  subject { described_class.new(tags, encoding, tmpdir) }
14
9
 
15
- it "can get current file io" do
16
- subject.get_file(prefix) do |file|
17
- expect(file).to be_kind_of(LogStash::Outputs::Qingstor::TemporaryFile)
18
- end
19
- end
10
+ let(:tags) { %w[tag1 tag2 tag3] }
11
+ let(:encoding) { 'none' }
12
+ let(:tmpdir) { File.join(Dir.tmpdir, 'lg2qs') }
13
+ let(:prefix) { 'aprefix' }
14
+
15
+ it 'can get current file io' do
16
+ subject.get_file(prefix) do |file|
17
+ expect(file).to be_kind_of(LogStash::Outputs::Qingstor::TemporaryFile)
18
+ end
19
+ end
20
20
 
21
- it "can get current file factory" do
22
- subject.get_factory(prefix) do |factory|
23
- expect(factory).to be_kind_of(LogStash::Outputs::Qingstor::TemporaryFileFactory)
24
- end
25
- end
26
- end
21
+ it 'can get current file factory' do
22
+ subject.get_factory(prefix) do |factory|
23
+ expect(factory).to be_kind_of(
24
+ LogStash::Outputs::Qingstor::TemporaryFileFactory
25
+ )
26
+ end
27
+ end
28
+ end
@@ -1,21 +1,23 @@
1
1
  # encoding: utf-8
2
- require "logstash/devutils/rspec/spec_helper"
3
- require "logstash/outputs/qingstor/qingstor_validator"
4
- require_relative "../qs_access_helper"
2
+
3
+ require 'logstash/devutils/rspec/spec_helper'
4
+ require 'logstash/outputs/qingstor/qingstor_validator'
5
+ require_relative '../qs_access_helper'
5
6
 
6
7
  describe LogStash::Outputs::Qingstor::QingstorValidator do
7
- let(:normal_prefix) { "super/bucket" }
8
- let(:wrong_prefix1) { "/wrong/prefix" }
8
+ let(:normal_prefix) { 'super/bucket' }
9
+ let(:wrong_prefix1) { '/wrong/prefix' }
9
10
  let(:wrong_prefix2) { normal_prefix * 100 }
10
11
  let(:bucket) { qs_bucket_init }
11
12
 
12
- it "raise error if the prefix is not valid" do
13
- expect{ described_class.prefix_valid?(wrong_prefix1) }.to raise_error(LogStash::ConfigurationError)
14
- expect{ described_class.prefix_valid?(wrong_prefix2) }.to raise_error(LogStash::ConfigurationError)
13
+ it 'raise error if the prefix is not valid' do
14
+ expect { described_class.prefix_valid?(wrong_prefix1) }
15
+ .to raise_error(LogStash::ConfigurationError)
16
+ expect { described_class.prefix_valid?(wrong_prefix2) }
17
+ .to raise_error(LogStash::ConfigurationError)
15
18
  end
16
19
 
17
- it "return true if the prefix is valid" do
20
+ it 'return true if the prefix is valid' do
18
21
  expect(described_class.prefix_valid?(normal_prefix)).to be_truthy
19
- end
20
-
21
- end
22
+ end
23
+ end