fluent-plugin-azurestorage-gen2 0.2.8 → 0.3.2

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: 46b6cf60479daf8f64e5196ad36332a11591220e
4
- data.tar.gz: 09aec8214be51d7be9ce4b2e7350e145d4b0fb51
3
+ metadata.gz: c9dfe2426009f9375ce47d7285a6030af693c148
4
+ data.tar.gz: 9e76fe1f92164e6e3807482f04d7f2cf6fecc19b
5
5
  SHA512:
6
- metadata.gz: a3f4d5c6245c11e5f8b4b33d26825a3d9f93796d553a1ac1d55c931e891762467c22abc228f546d7c2efdf107c3cc471d47dc6bc0114bd1f5c1dced3a6b30bae
7
- data.tar.gz: 67b751890b5aee2086d6d617b41d4da6883d8cfa9e77acc2ac7de54f58e457725cb718606a65ec385972fed1a24518cc9d981f15a454393b1e08b31b662735b9
6
+ metadata.gz: dbdac55653f0e83acde54dc2ace5e58e43f6954b84bb0179526a4230adf59619be469f313508ecbeb772dc447473cd62e9d3fbaff9cb3af5d45b3d1ba6fdab45
7
+ data.tar.gz: 95475a64f3447e017da418c4faa87dabc932c12205b2050e9e4dd1382128f919415e466a94c68a90bd22be6be7cc3aaf4a426a9ffb1d4efff2bbb4a87925ef81
data/README.md CHANGED
@@ -31,6 +31,7 @@ $ gem install fluent-plugin-azurestorage-gen2
31
31
  azure_storage_account mystorageabfs
32
32
  azure_container mycontainer
33
33
  azure_instance_msi /subscriptions/mysubscriptionid
34
+ azure_client_id <msi client id>
34
35
  azure_object_key_format %{path}-%{index}.%{file_extension}
35
36
  azure_oauth_refresh_interval 3600
36
37
  time_slice_format %Y%m%d-%H
@@ -92,6 +93,14 @@ Your Azure Storage Access Key(Primary or Secondary). This also can be got from A
92
93
 
93
94
  Your Azure Managed Service Identity ID. When storage key authentication is not used, the plugin uses OAuth2 to authenticate as given MSI. This authentication method only works on Azure VM. If the VM has only one MSI assigned, this parameter becomes optional and the only MSI will be used. Otherwise this parameter is required.
94
95
 
96
+ ### azure_client_id
97
+
98
+ Azure AD client id is a specific explicit identity to use when authenticating to Azure AD. Mutually exclusive with azure_object_id and azure_instance_msi. (for now, you need to define next to `azure_instance_msi`)
99
+
100
+ ### azure_object_id
101
+
102
+ Azure AD object id is a specific explicit identity to use when authenticating to Azure AD. Mutually exclusive with azure_client_id and azure_instance_msi. (for now, you need to define next to `azure_instance_msi`)
103
+
95
104
  ### azure_oauth_tenant_id (Preview)
96
105
 
97
106
  Azure account tenant id from your Azure Directory. Required if OAuth based credential mechanism is used.
@@ -140,6 +149,10 @@ If that setting is disabled, the worker won't fail on initialization (getting fi
140
149
 
141
150
  The defaultt `url_domain_suffix` is `.dfs.core.windows.net`, you can override this in case of private endpoints.
142
151
 
152
+ ### url_storage_resource
153
+
154
+ The url that is used during accessing a resource. Default value: `https://storage.azure.com/`
155
+
143
156
  ### azure_object_key_format
144
157
 
145
158
  The format of Azure Storage object keys. You can use several built-in variables:
@@ -148,6 +161,7 @@ The format of Azure Storage object keys. You can use several built-in variables:
148
161
  - %{time_slice}
149
162
  - %{index}
150
163
  - %{file_extension}
164
+ - %{upload_timestamp}
151
165
 
152
166
  to decide keys dynamically.
153
167
 
@@ -155,6 +169,7 @@ to decide keys dynamically.
155
169
  %{time_slice} is the time-slice in text that are formatted with *time_slice_format*.
156
170
  %{index} is the sequential number starts from 0, increments when multiple files are uploaded to Azure Storage in the same time slice.
157
171
  %{file_extention} is always "gz" for now.
172
+ %{upload_timestamp} is an upload timestamp in text that are formatted with *upload_timestamp_format*. Difference between time_slice and upload_timestamp is that the second one is the actual system timestamp (other one is from the metadata)
158
173
 
159
174
  The default format is "%{path}%{time_slice}_%{index}.%{file_extension}".
160
175
 
@@ -279,10 +294,30 @@ Format of the time used as the file name. Default is '%Y%m%d'. Use '%Y%m%d%H' to
279
294
 
280
295
  The time to wait old logs. Default is 10 minutes.
281
296
 
297
+ ### upload_timestamp_format
298
+
299
+ Format of the upload timestamp used as the file name. Can be used instead of index in case of `write_only` option is enabled. Default value is '%H%M%S%L'.
300
+
282
301
  ### utc
283
302
 
284
303
  Use UTC instead of local time.
285
304
 
305
+ ### write_only
306
+
307
+ If that option is enabled, HEAD calls are skipped during blob operations. (so make sure to set the chunk limit to 4MB in order to avoid HEAD operation because of the append operation needs the last position of the uploaded blobs).
308
+
309
+ ### proxy_url
310
+
311
+ Proxy URL for Azure endpoint.
312
+
313
+ ### proxy_username
314
+
315
+ Proxy username for Azure proxy endpoint (used only if `proxy_url` is filled)
316
+
317
+ ### proxy_password
318
+
319
+ Proxy password for Azure `proxy_username` (used only if `proxy_url` is filled)
320
+
286
321
  ## TODOs
287
322
 
288
323
  - add storage key support
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.8
1
+ 0.3.2
@@ -24,6 +24,8 @@ module Fluent::Plugin
24
24
  config_param :azure_storage_account, :string, :default => nil
25
25
  config_param :azure_storage_access_key, :string, :default => nil, :secret => true
26
26
  config_param :azure_instance_msi, :string, :default => nil
27
+ config_param :azure_client_id, :string, :default => nil
28
+ config_param :azure_object_id, :string, :default => nil
27
29
  config_param :azure_oauth_app_id, :string, :default => nil, :secret => true
28
30
  config_param :azure_oauth_secret, :string, :default => nil, :secret => true
29
31
  config_param :azure_oauth_tenant_id, :string, :default => nil
@@ -39,9 +41,16 @@ module Fluent::Plugin
39
41
  config_param :enable_retry, :bool, :default => false
40
42
  config_param :startup_fail_on_error, :bool, :default => true
41
43
  config_param :url_domain_suffix, :string, :default => '.dfs.core.windows.net'
44
+ config_param :url_storage_resource, :string, :default => 'https://storage.azure.com/'
42
45
  config_param :format, :string, :default => "out_file"
43
46
  config_param :time_slice_format, :string, :default => '%Y%m%d'
47
+ config_param :hex_random_length, :integer, default: 4
44
48
  config_param :command_parameter, :string, :default => nil
49
+ config_param :proxy_url, :string, :default => nil
50
+ config_param :proxy_username, :string, :default => nil
51
+ config_param :proxy_password, :string, :default => nil, :secret => true
52
+ config_param :write_only, :bool, :default => false
53
+ config_param :upload_timestamp_format, :string, :default => '%H%M%S%L'
45
54
 
46
55
  DEFAULT_FORMAT_TYPE = "out_file"
47
56
  ACCESS_TOKEN_API_VERSION = "2018-02-01"
@@ -51,7 +60,7 @@ module Fluent::Plugin
51
60
  config_section :format do
52
61
  config_set_default :@type, DEFAULT_FORMAT_TYPE
53
62
  end
54
-
63
+
55
64
  config_section :buffer do
56
65
  config_set_default :chunk_keys, ['time']
57
66
  config_set_default :timekey, (60 * 60 * 24)
@@ -74,17 +83,7 @@ module Fluent::Plugin
74
83
  end
75
84
 
76
85
  @formatter = formatter_create
77
-
78
- if @localtime
79
- @path_slicer = Proc.new {|path|
80
- Time.now.strftime(path)
81
- }
82
- else
83
- @path_slicer = Proc.new {|path|
84
- Time.now.utc.strftime(path)
85
- }
86
- end
87
-
86
+
88
87
  if @azure_container.nil?
89
88
  raise Fluent::ConfigError, "azure_container is needed"
90
89
  end
@@ -98,7 +97,7 @@ module Fluent::Plugin
98
97
  else
99
98
  @final_file_extension = @compressor.ext
100
99
  end
101
-
100
+ @values_for_object_chunk = {}
102
101
  end
103
102
 
104
103
  def multi_workers_ready?
@@ -110,12 +109,20 @@ module Fluent::Plugin
110
109
  if !@skip_container_check
111
110
  if @failsafe_container_check
112
111
  begin
113
- ensure_container
112
+ if @write_only && @auto_create_container
113
+ create_container
114
+ else
115
+ ensure_container
116
+ end
114
117
  rescue Exception => e
115
118
  log.warn("#{e.message}, container list/create failsafe is enabled. Continue without those operations.")
116
119
  end
117
120
  else
118
- ensure_container
121
+ if @write_only && @auto_create_container
122
+ create_container
123
+ else
124
+ ensure_container
125
+ end
119
126
  end
120
127
  end
121
128
  super
@@ -127,17 +134,16 @@ module Fluent::Plugin
127
134
  end
128
135
 
129
136
  def write(chunk)
130
- metadata = chunk.metadata
131
137
  if @store_as.nil? || @store_as == "none"
132
- generate_log_name(metadata, @current_index)
138
+ generate_log_name(chunk, @current_index)
133
139
  if @last_azure_storage_path != @azure_storage_path
134
140
  @current_index = 0
135
- generate_log_name(metadata, @current_index)
141
+ generate_log_name(chunk, @current_index)
136
142
  end
137
143
  raw_data = chunk.read
138
144
  unless raw_data.empty?
139
145
  log.debug "azurestorage_gen2: processing raw data", chunk_id: dump_unique_id_hex(chunk.unique_id)
140
- upload_blob(raw_data, metadata)
146
+ upload_blob(raw_data, chunk)
141
147
  end
142
148
  chunk.close rescue nil
143
149
  @last_azure_storage_path = @azure_storage_path
@@ -147,51 +153,76 @@ module Fluent::Plugin
147
153
  begin
148
154
  @compressor.compress(chunk, tmp)
149
155
  tmp.rewind
150
- generate_log_name(metadata, @current_index)
156
+ generate_log_name(chunk, @current_index)
151
157
  if @last_azure_storage_path != @azure_storage_path
152
158
  @current_index = 0
153
- generate_log_name(metadata, @current_index)
159
+ generate_log_name(chunk, @current_index)
154
160
  end
155
161
  log.debug "azurestorage_gen2: Start uploading temp file: #{tmp.path}"
156
162
  content = File.open(tmp.path, 'rb') { |file| file.read }
157
- upload_blob(content, metadata)
163
+ upload_blob(content, chunk)
158
164
  @last_azure_storage_path = @azure_storage_path
159
165
  ensure
160
166
  tmp.close(true) rescue nil
161
167
  end
168
+ @values_for_object_chunk.delete(chunk.unique_id)
162
169
  end
163
170
 
164
171
  end
165
172
 
166
173
  private
167
- def upload_blob(content, metadata)
174
+ def upload_blob(content, chunk)
168
175
  log.debug "azurestorage_gen2: Uploading blob: #{@azure_storage_path}"
169
- existing_content_length = get_blob_properties(@azure_storage_path)
170
- if existing_content_length == 0
176
+ if @write_only
171
177
  create_blob(@azure_storage_path)
178
+ append_blob(content, chunk, 0)
179
+ else
180
+ existing_content_length = get_blob_properties(@azure_storage_path)
181
+ if existing_content_length == 0
182
+ create_blob(@azure_storage_path)
183
+ end
184
+ append_blob(content, chunk, existing_content_length)
172
185
  end
173
- append_blob(content, metadata, existing_content_length)
174
186
  end
175
187
 
176
188
  private
177
- def generate_log_name(metadata, index)
189
+ def generate_log_name(chunk, index)
190
+ metadata = chunk.metadata
178
191
  time_slice = if metadata.timekey.nil?
179
192
  ''.freeze
180
193
  else
181
194
  Time.at(metadata.timekey).utc.strftime(@time_slice_format)
182
195
  end
183
- path = @path_slicer.call(@path)
184
- values_for_object_key = {
185
- "%{path}" => path,
186
- "%{time_slice}" => time_slice,
196
+ if @localtime
197
+ hms_slicer = Time.now.strftime("%H%M%S")
198
+ upload_timestamp = Time.now.strftime(@upload_timestamp_format)
199
+ else
200
+ hms_slicer = Time.now.utc.strftime("%H%M%S")
201
+ upload_timestamp = Time.now.utc.strftime(@upload_timestamp_format)
202
+ end
203
+
204
+ @values_for_object_chunk[chunk.unique_id] ||= {
205
+ "%{hex_random}" => hex_random(chunk),
206
+ }
207
+ values_for_object_key_pre = {
208
+ "%{path}" => @path,
187
209
  "%{index}" => index,
188
210
  "%{uuid_flush}" => uuid_random,
189
- "%{file_extension}" => @final_file_extension
211
+ "%{file_extension}" => @final_file_extension,
212
+ "%{upload_timestamp}" => upload_timestamp,
190
213
  }
191
- storage_path = @azure_object_key_format.gsub(%r(%{[^}]+}), values_for_object_key)
192
- extracted_path = extract_placeholders(storage_path, metadata)
193
- extracted_path = "/" + extracted_path unless extracted_path.start_with?("/")
194
- @azure_storage_path = extracted_path
214
+ values_for_object_key_post = {
215
+ "%{date_slice}" => time_slice,
216
+ "%{time_slice}" => time_slice,
217
+ "%{hms_slice}" => hms_slicer,
218
+ }.merge!(@values_for_object_chunk[chunk.unique_id])
219
+ storage_path = @azure_object_key_format.gsub(%r(%{[^}]+})) do |matched_key|
220
+ values_for_object_key_pre.fetch(matched_key, matched_key)
221
+ end
222
+ storage_path = extract_placeholders(storage_path, chunk)
223
+ storage_path = storage_path.gsub(%r(%{[^}]+}), values_for_object_key_post)
224
+ storage_path = "/" + storage_path unless storage_path.start_with?("/")
225
+ @azure_storage_path = storage_path
195
226
  end
196
227
 
197
228
  def setup_access_token
@@ -243,11 +274,22 @@ module Fluent::Plugin
243
274
  # https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/tutorial-linux-vm-access-storage#get-an-access-token-and-use-it-to-call-azure-storage
244
275
  private
245
276
  def acquire_access_token_msi
246
- params = { :"api-version" => ACCESS_TOKEN_API_VERSION, :resource => "https://storage.azure.com/" }
277
+ params = { :"api-version" => ACCESS_TOKEN_API_VERSION, :resource => "#{@url_storage_resource}" }
247
278
  unless @azure_instance_msi.nil?
248
279
  params[:msi_res_id] = @azure_instance_msi
249
280
  end
250
- request = Typhoeus::Request.new("http://169.254.169.254/metadata/identity/oauth2/token", params: params, headers: { Metadata: "true"})
281
+ unless @azure_client_id.nil?
282
+ params[:client_id] = @azure_client_id
283
+ end
284
+ unless @azure_object_id.nil?
285
+ params[:object_id] = @azure_object_id
286
+ end
287
+ req_opts = {
288
+ :params => params,
289
+ :headers => { Metadata: "true" }
290
+ }
291
+ add_proxy_options(req_opts)
292
+ request = Typhoeus::Request.new("http://169.254.169.254/metadata/identity/oauth2/token", req_opts)
251
293
  request.on_complete do |response|
252
294
  if response.success?
253
295
  data = JSON.parse(response.body)
@@ -262,10 +304,16 @@ module Fluent::Plugin
262
304
 
263
305
  private
264
306
  def acquire_access_token_oauth_app
265
- params = { :"api-version" => ACCESS_TOKEN_API_VERSION, :resource => "https://storage.azure.com/"}
307
+ params = { :"api-version" => ACCESS_TOKEN_API_VERSION, :resource => "#{@url_storage_resource}"}
266
308
  headers = {:"Content-Type" => "application/x-www-form-urlencoded"}
267
- content = "grant_type=client_credentials&client_id=#{@azure_oauth_app_id}&client_secret=#{@azure_oauth_secret}&resource=https://storage.azure.com/"
268
- request = Typhoeus::Request.new("https://login.microsoftonline.com/#{@azure_oauth_tenant_id}/oauth2/token", :body => content, :headers => headers)
309
+ content = "grant_type=client_credentials&client_id=#{@azure_oauth_app_id}&client_secret=#{@azure_oauth_secret}&resource=#{@url_storage_resource}"
310
+ req_opts = {
311
+ :params => params,
312
+ :body => content,
313
+ :headers => headers
314
+ }
315
+ add_proxy_options(req_opts)
316
+ request = Typhoeus::Request.new("https://login.microsoftonline.com/#{@azure_oauth_tenant_id}/oauth2/token", req_opts)
269
317
  request.on_complete do |response|
270
318
  if response.success?
271
319
  data = JSON.parse(response.body)
@@ -280,7 +328,7 @@ module Fluent::Plugin
280
328
 
281
329
  private
282
330
  def acquire_access_token_by_az
283
- access_token=`az account get-access-token --resource https://storage.azure.com/ --query accessToken -o tsv`
331
+ access_token=`az account get-access-token --resource #{@url_storage_resource} --query accessToken -o tsv`
284
332
  log.debug "azurestorage_gen2: Token response: #{access_token}"
285
333
  @azure_access_token = access_token.chomp
286
334
  end
@@ -292,7 +340,13 @@ module Fluent::Plugin
292
340
  params = {:resource => "filesystem" }
293
341
  auth_header = create_auth_header("head", datestamp, "#{@azure_container}", headers, params)
294
342
  headers[:Authorization] = auth_header
295
- request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}", :method => :head, :params => params, :headers=> headers)
343
+ req_opts = {
344
+ :method => :head,
345
+ :params => params,
346
+ :headers => headers
347
+ }
348
+ add_proxy_options(req_opts)
349
+ request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}", req_opts)
296
350
  request.on_complete do |response|
297
351
  if response.success?
298
352
  log.info "azurestorage_gen2: Container '#{@azure_container}' exists."
@@ -319,7 +373,13 @@ module Fluent::Plugin
319
373
  params = {:resource => "filesystem" }
320
374
  auth_header = create_auth_header("put", datestamp, "#{@azure_container}", headers, params)
321
375
  headers[:Authorization] = auth_header
322
- request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}", :method => :put, :params => params, :headers=> headers)
376
+ req_opts = {
377
+ :method => :put,
378
+ :params => params,
379
+ :headers => headers
380
+ }
381
+ add_proxy_options(req_opts)
382
+ request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}", req_opts)
323
383
  request.on_complete do |response|
324
384
  if response.success?
325
385
  log.debug "azurestorage_gen2: Container '#{@azure_container}' created, response code: #{response.code}"
@@ -339,7 +399,13 @@ module Fluent::Plugin
339
399
  params = {:resource => "file", :recursive => "false"}
340
400
  auth_header = create_auth_header("put", datestamp, "#{@azure_container}#{blob_path}", headers, params)
341
401
  headers[:Authorization] = auth_header
342
- request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", :method => :put, :params => params, :headers=> headers)
402
+ req_opts = {
403
+ :method => :put,
404
+ :params => params,
405
+ :headers => headers
406
+ }
407
+ add_proxy_options(req_opts)
408
+ request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", req_opts)
343
409
  request.on_complete do |response|
344
410
  if response.success?
345
411
  log.debug "azurestorage_gen2: Blob '#{blob_path}' has been created, response code: #{response.code}"
@@ -362,7 +428,14 @@ module Fluent::Plugin
362
428
  params = {:action => "append", :position => "#{position}"}
363
429
  auth_header = create_auth_header("patch", datestamp, "#{@azure_container}#{blob_path}", headers, params)
364
430
  headers[:Authorization] = auth_header
365
- request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", :method => :patch, :headers=> headers, :params => params, :body => content)
431
+ req_opts = {
432
+ :method => :patch,
433
+ :params => params,
434
+ :headers => headers,
435
+ :body => content
436
+ }
437
+ add_proxy_options(req_opts)
438
+ request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", req_opts)
366
439
  request.on_complete do |response|
367
440
  if response.success?
368
441
  log.debug "azurestorage_gen2: Blob '#{blob_path}' has been appended, response code: #{response.code}"
@@ -387,7 +460,13 @@ module Fluent::Plugin
387
460
  params = {:action => "flush", :position => "#{position}"}
388
461
  auth_header = create_auth_header("patch", datestamp, "#{@azure_container}#{blob_path}",headers, params)
389
462
  headers[:Authorization] = auth_header
390
- request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", :method => :patch, :params => params, :headers=> headers)
463
+ req_opts = {
464
+ :method => :patch,
465
+ :params => params,
466
+ :headers => headers
467
+ }
468
+ add_proxy_options(req_opts)
469
+ request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", req_opts)
391
470
  request.on_complete do |response|
392
471
  if response.success?
393
472
  log.debug "azurestorage_gen2: Blob '#{blob_path}' flush was successful, response code: #{response.code}"
@@ -408,7 +487,13 @@ module Fluent::Plugin
408
487
  content_length = -1
409
488
  auth_header = create_auth_header("head", datestamp, "#{@azure_container}#{blob_path}", headers, params)
410
489
  headers[:Authorization] = auth_header
411
- request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", :method => :head, :params => params, :headers=> headers)
490
+ req_opts = {
491
+ :method => :head,
492
+ :params => params,
493
+ :headers => headers
494
+ }
495
+ add_proxy_options(req_opts)
496
+ request = Typhoeus::Request.new("https://#{azure_storage_account}#{@url_domain_suffix}/#{@azure_container}#{blob_path}", req_opts)
412
497
  request.on_complete do |response|
413
498
  if response.success?
414
499
  log.debug "azurestorage_gen2: Get blob properties for '#{blob_path}', response headers: #{response.headers}"
@@ -427,7 +512,7 @@ module Fluent::Plugin
427
512
  end
428
513
 
429
514
  private
430
- def append_blob(content, metadata, existing_content_length)
515
+ def append_blob(content, chunk, existing_content_length)
431
516
  position = 0
432
517
  log.debug "azurestorage_gen2: append_blob.start: Content size: #{content.length}"
433
518
  loop do
@@ -476,6 +561,16 @@ module Fluent::Plugin
476
561
  "SharedKey #{@azure_storage_account}:#{signed(method, datestamp, resource, headers, params)}"
477
562
  end
478
563
  end
564
+
565
+ private
566
+ def add_proxy_options(req_opts = {})
567
+ unless @proxy_url.nil?
568
+ req_opts[:proxy] = @proxy_url
569
+ unless @proxy_username.nil? || @proxy_password.nil?
570
+ req_opts[:proxyuserpwd] = "#{@proxy_username}:#{@proxy_password}"
571
+ end
572
+ end
573
+ end
479
574
 
480
575
  private
481
576
  def signed(method, datestamp, resource, headers, params)
@@ -545,6 +640,12 @@ module Fluent::Plugin
545
640
  require 'uuidtools'
546
641
  ::UUIDTools::UUID.random_create.to_s
547
642
  end
643
+
644
+ def hex_random(chunk)
645
+ unique_hex = Fluent::UniqueId.hex(chunk.unique_id)
646
+ unique_hex.reverse!
647
+ unique_hex[0...@hex_random_length]
648
+ end
548
649
 
549
650
  def timekey_to_timeformat(timekey)
550
651
  case timekey
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-azurestorage-gen2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Szabo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-21 00:00:00.000000000 Z
11
+ date: 2021-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd