fluent-plugin-azurestorage-gen2 0.1.4 → 0.2.2

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: 13b891a2c06d9a6a18d088c8cf02eb781d3538eb
4
- data.tar.gz: cc89a73ec41eed32b5a7f3a4d104c3ac80422642
3
+ metadata.gz: c631dda137f661c5692855eb46d97696df14a5e0
4
+ data.tar.gz: 174ace2e26b75f25b12a38d3c76726d3526f0866
5
5
  SHA512:
6
- metadata.gz: da9ade031001af9fea91952af3da3fea6fa32dac029b4b2ae84cb9ac92c2b68e2fd7f9232380ec38fd96990ad53b07d9a16ec11699c12ed4b3e2978a72c03364
7
- data.tar.gz: 76d5f0f943d2647b388852d4c4d274c0af6c8cfae9b3440afaed6b5cb4db240106efe106e974cb8ad744fe7f3ecb4deee143271e42ef67f2f9db184427b96143
6
+ metadata.gz: 5f135ffbe42f292666e66bca2b84a8c1f49d3ddf727460e376c95658b0382419a9008b110371d48314ccef6af0dc2f3cff5b0ae64730ae29222571dd20333163
7
+ data.tar.gz: e81ba7ac31051ac5813ab4f3c845ee866f7dce3061c16a72fc5f3164e4b53c9c345c1135820762671162f092b195191a93ff6650a2562fc61cb12ea9a4b97ff2
data/Makefile CHANGED
@@ -8,8 +8,6 @@ install: gem
8
8
  push: gem
9
9
  gem push fluent-plugin-azurestorage-gen2*.gem
10
10
 
11
- tag-and-branch:
11
+ tag:
12
12
  git tag "v$$(cat VERSION)" $(RELEASE_COMMIT)
13
- git checkout -b "release/$$(cat VERSION)" $(RELEASE_COMMIT)
14
- git push origin "v$$(cat VERSION)"
15
- git push -u origin "release/$$(cat VERSION)"
13
+ git push origin "v$$(cat VERSION)"
data/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  | fluent-plugin-azurestorage-gen2 | fluentd | ruby |
11
11
  |------------------------|---------|------|
12
- | >= 0.1.3 | >= v0.14.0 | >= 2.4 |
12
+ | >= 0.1.0 | >= v0.14.0 | >= 2.4 |
13
13
 
14
14
  ## Overview
15
15
 
@@ -34,9 +34,11 @@ $ gem install fluent-plugin-azurestorage-gen2
34
34
  azure_object_key_format %{path}-%{index}.%{file_extension}
35
35
  azure_oauth_refresh_interval 3600
36
36
  time_slice_format %Y%m%d-%H
37
- file_extension log
37
+ file_extension log # only used with store_as none
38
38
  path "/cluster-logs/myfolder/${tag[1]}-#{Socket.gethostname}-%M"
39
39
  auto_create_container true
40
+ store_as gzip
41
+ format single_value
40
42
  <buffer tag,time>
41
43
  @type file
42
44
  path /var/log/fluent/azurestorage-buffer
@@ -60,9 +62,10 @@ $ gem install fluent-plugin-azurestorage-gen2
60
62
  azure_oauth_secret <my client secret>
61
63
  azure_oauth_refresh_interval 3600
62
64
  time_slice_format %Y%m%d-%H
63
- file_extension log
64
65
  path "/cluster-logs/myfolder/${tag[1]}-#{Socket.gethostname}-%M"
66
+ store_as gzip
65
67
  auto_create_container true
68
+ format single_value
66
69
  <buffer tag,time>
67
70
  @type file
68
71
  path /var/log/fluent/azurestorage-buffer
@@ -103,7 +106,7 @@ OAuth client secret that is used for OAuth based authentication. Required if OAu
103
106
 
104
107
  ### azure_oauth_refresh_interval
105
108
 
106
- OAuth2 access token refreshment interval in second. Only applies when MSI / OAuth authentication is used.
109
+ OAuth2 access token refreshment interval in second. Only applies when MSI / OAuth authentication is used. (default value is 59 minutes)
107
110
 
108
111
  ### azure_oauth_use_azure_cli (Preview)
109
112
 
@@ -117,6 +120,14 @@ Azure Storage Container name
117
120
 
118
121
  This plugin create container if not exist when you set 'auto_create_container' to true.
119
122
 
123
+ ### skip_container_check
124
+
125
+ You can skip the initial container listing (and container creation) operations at startup. That can be useful if the user is not allowed to perform this operation.
126
+
127
+ ### enable_retry
128
+
129
+ If you set this option, operations can be retried in the buffer. Default value is false. (Currently only flush command is supported)
130
+
120
131
  ### azure_object_key_format
121
132
 
122
133
  The format of Azure Storage object keys. You can use several built-in variables:
@@ -169,13 +180,13 @@ azure_object_key_format %{path}/events/ts=%{time_slice}/events_%{index}-%{hostna
169
180
 
170
181
  ### file_extension
171
182
 
172
- File extension for the uploaded files. Only uses if `store_as` is not set, or set as `none`
183
+ File extension for the uploaded files. Only used if `store_as` is not set, or set as `none`
173
184
 
174
185
  ### store_as
175
186
 
176
187
  Archive format on Azure Storage. You can use following types:
177
188
 
178
- - none (default - no tmp file creation for log processing)
189
+ - none (default - no tmp file creation for log processing, use with json or single value format)
179
190
  - gzip
180
191
  - json
181
192
  - text
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.2.2
@@ -24,6 +24,7 @@ module Fluent
24
24
  chunk.path
25
25
  else
26
26
  w = Tempfile.new("chunk-gzip-tmp")
27
+ w.binmode
27
28
  chunk.write_to(w)
28
29
  w.close
29
30
  w.path
@@ -20,6 +20,7 @@ module Fluent
20
20
 
21
21
  def compress(chunk, tmp)
22
22
  w = Tempfile.new("chunk-xz-tmp")
23
+ w.binmode
23
24
  chunk.write_to(w)
24
25
  w.close
25
26
 
@@ -20,6 +20,7 @@ module Fluent
20
20
 
21
21
  def compress(chunk, tmp)
22
22
  w = Tempfile.new("chunk-tmp")
23
+ w.binmode
23
24
  chunk.write_to(w)
24
25
  w.close
25
26
 
@@ -27,16 +27,17 @@ module Fluent::Plugin
27
27
  config_param :azure_oauth_secret, :string, :default => nil, :secret => true
28
28
  config_param :azure_oauth_tenant_id, :string, :default => nil
29
29
  config_param :azure_oauth_use_azure_cli, :bool, :default => false
30
- config_param :azure_oauth_refresh_interval, :integer, :default => 60 * 60 # one hour
30
+ config_param :azure_oauth_refresh_interval, :integer, :default => 60 * 59 # 59 minutes, do not wait one hour
31
31
  config_param :azure_container, :string, :default => nil
32
32
  config_param :azure_object_key_format, :string, :default => "%{path}%{time_slice}_%{index}.%{file_extension}"
33
33
  config_param :file_extension, :string, :default => "log"
34
34
  config_param :store_as, :string, :default => "none"
35
35
  config_param :auto_create_container, :bool, :default => false
36
+ config_param :skip_container_check, :bool, :default => false
37
+ config_param :enable_retry, :bool, :default => false
36
38
  config_param :format, :string, :default => "out_file"
37
39
  config_param :time_slice_format, :string, :default => '%Y%m%d'
38
40
  config_param :command_parameter, :string, :default => nil
39
- config_param :message_field, :string, :default => nil
40
41
 
41
42
  DEFAULT_FORMAT_TYPE = "out_file"
42
43
  URL_DOMAIN_SUFFIX = '.dfs.core.windows.net'
@@ -57,13 +58,17 @@ module Fluent::Plugin
57
58
  compat_parameters_convert(conf, :buffer, :formatter, :inject)
58
59
  super
59
60
 
60
- begin
61
- @compressor = COMPRESSOR_REGISTRY.lookup(@store_as).new(:buffer_type => @buffer_type, :log => log)
62
- rescue => e
63
- log.warn "#{@store_as} not found. Use 'text' instead"
64
- @compressor = TextCompressor.new
61
+ if @store_as.nil? || @store_as == "none"
62
+ log.info "azurestorage_gen2: Compression is disabled (store_as: #{@store_as})"
63
+ else
64
+ begin
65
+ @compressor = COMPRESSOR_REGISTRY.lookup(@store_as).new(:buffer_type => @buffer_type, :log => log)
66
+ rescue => e
67
+ log.warn "#{@store_as} not found. Use 'text' instead"
68
+ @compressor = TextCompressor.new
69
+ end
70
+ @compressor.configure(conf)
65
71
  end
66
- @compressor.configure(conf)
67
72
 
68
73
  @formatter = formatter_create
69
74
 
@@ -84,11 +89,10 @@ module Fluent::Plugin
84
89
  @azure_storage_path = ''
85
90
  @last_azure_storage_path = ''
86
91
  @current_index = 0
92
+
87
93
  if @store_as.nil? || @store_as == "none"
88
- @blob_content_type = "text/plain"
89
94
  @final_file_extension = @file_extension
90
95
  else
91
- @blob_content_type = @compressor.content_type
92
96
  @final_file_extension = @compressor.ext
93
97
  end
94
98
 
@@ -100,48 +104,49 @@ module Fluent::Plugin
100
104
 
101
105
  def start
102
106
  setup_access_token
103
- ensure_container
107
+ if !@skip_container_check
108
+ ensure_container
109
+ end
104
110
  super
105
111
  end
106
112
 
113
+ def format(tag, time, record)
114
+ r = inject_values_to_record(tag, time, record)
115
+ @formatter.format(tag, time, r)
116
+ end
117
+
107
118
  def write(chunk)
108
119
  metadata = chunk.metadata
109
120
  if @store_as.nil? || @store_as == "none"
110
- raw_data=''
111
121
  generate_log_name(metadata, @current_index)
112
122
  if @last_azure_storage_path != @azure_storage_path
113
123
  @current_index = 0
114
124
  generate_log_name(metadata, @current_index)
115
125
  end
116
- chunk.each do |emit_time, record|
117
- if @message_field.nil? || @message_field.empty?
118
- raw_data << "#{Yajl.dump(record)}\n"
119
- elsif record.key?(@message_field)
120
- line = record[@message_field].chomp
121
- raw_data << "#{line}\n"
122
- end
123
- end
124
- raw_data = raw_data.chomp
126
+ raw_data = chunk.read
125
127
  unless raw_data.empty?
128
+ log.debug "azurestorage_gen2: processing raw data", chunk_id: dump_unique_id_hex(chunk.unique_id)
126
129
  upload_blob(raw_data, metadata)
127
130
  end
131
+ chunk.close rescue nil
128
132
  @last_azure_storage_path = @azure_storage_path
129
133
  else
130
134
  tmp = Tempfile.new("azure-")
135
+ tmp.binmode
131
136
  begin
132
137
  @compressor.compress(chunk, tmp)
133
- tmp.close
138
+ tmp.rewind
134
139
  generate_log_name(metadata, @current_index)
135
140
  if @last_azure_storage_path != @azure_storage_path
136
141
  @current_index = 0
137
142
  generate_log_name(metadata, @current_index)
138
143
  end
139
- log.debug "Start uploading temp file: #{tmp.path}"
144
+ log.debug "azurestorage_gen2: Start uploading temp file: #{tmp.path}"
140
145
  content = File.open(tmp.path, 'rb') { |file| file.read }
141
146
  upload_blob(content, metadata)
142
147
  @last_azure_storage_path = @azure_storage_path
143
148
  ensure
144
- tmp.unlink
149
+ tmp.close(true) rescue nil
145
150
  end
146
151
  end
147
152
 
@@ -149,7 +154,7 @@ module Fluent::Plugin
149
154
 
150
155
  private
151
156
  def upload_blob(content, metadata)
152
- log.debug "azurestorage_gen2: Uploading blob: #{@azure_storage_path}"
157
+ log.debug "azurestorage_gen2: Uploading blob: #{@azure_storage_path}"
153
158
  existing_content_length = get_blob_properties(@azure_storage_path)
154
159
  if existing_content_length == 0
155
160
  create_blob(@azure_storage_path)
@@ -157,11 +162,6 @@ module Fluent::Plugin
157
162
  append_blob(content, metadata, existing_content_length)
158
163
  end
159
164
 
160
- def format(tag, time, record)
161
- r = inject_values_to_record(tag, time, record)
162
- @formatter.format(tag, time, r)
163
- end
164
-
165
165
  private
166
166
  def generate_log_name(metadata, index)
167
167
  time_slice = if metadata.timekey.nil?
@@ -229,7 +229,7 @@ module Fluent::Plugin
229
229
  if response.success?
230
230
  data = JSON.parse(response.body)
231
231
  log.debug "azurestorage_gen2: Token response: #{data}"
232
- @azure_access_token = data["access_token"]
232
+ @azure_access_token = data["access_token"].chomp
233
233
  else
234
234
  raise Fluent::UnrecoverableError, "Failed to acquire access token. #{response.code}: #{response.body}"
235
235
  end
@@ -242,12 +242,12 @@ module Fluent::Plugin
242
242
  params = { :"api-version" => ACCESS_TOKEN_API_VERSION, :resource => "https://storage.azure.com/"}
243
243
  headers = {:"Content-Type" => "application/x-www-form-urlencoded"}
244
244
  content = "grant_type=client_credentials&client_id=#{@azure_oauth_app_id}&client_secret=#{@azure_oauth_secret}&resource=https://storage.azure.com/"
245
- request = Typhoeus::Request.new("https://login.microsoftonline.com/#{@azure_oauth_tenant_id}/oauth2/token", :body => content, :headers => headers, verbose: true)
245
+ request = Typhoeus::Request.new("https://login.microsoftonline.com/#{@azure_oauth_tenant_id}/oauth2/token", :body => content, :headers => headers)
246
246
  request.on_complete do |response|
247
247
  if response.success?
248
248
  data = JSON.parse(response.body)
249
249
  log.debug "azurestorage_gen2: Token response: #{data}"
250
- @azure_access_token = data["access_token"]
250
+ @azure_access_token = data["access_token"].chomp
251
251
  else
252
252
  raise Fluent::UnrecoverableError, "Failed to acquire access token. #{response.code}: #{response.body}"
253
253
  end
@@ -259,7 +259,7 @@ module Fluent::Plugin
259
259
  def acquire_access_token_by_az
260
260
  access_token=`az account get-access-token --resource https://storage.azure.com/ --query accessToken -o tsv`
261
261
  log.debug "azurestorage_gen2: Token response: #{access_token}"
262
- @azure_access_token = access_token
262
+ @azure_access_token = access_token.chomp
263
263
  end
264
264
 
265
265
  private
@@ -301,7 +301,7 @@ module Fluent::Plugin
301
301
  if response.success?
302
302
  log.debug "azurestorage_gen2: Container '#{@azure_container}' created, response code: #{response.code}"
303
303
  elsif response.timed_out?
304
- raise Fluent::UnrecoverableError, "Creating container '#{@azure_container}' request timed out."
304
+ raise Fluent::UnrecoverableError, "Creating container '#{@azure_container}' request timed out."
305
305
  else
306
306
  raise Fluent::UnrecoverableError, "Creating container request failed - code: #{response.code}, body: #{response.body}, headers: #{response.headers}"
307
307
  end
@@ -312,7 +312,7 @@ module Fluent::Plugin
312
312
  private
313
313
  def create_blob(blob_path)
314
314
  datestamp = create_request_date
315
- headers = {:"x-ms-version" => ABFS_API_VERSION, :"x-ms-date" => datestamp,:"Content-Length" => "0", :"Content-Type" => "application/json"}
315
+ headers = {:"x-ms-version" => ABFS_API_VERSION, :"x-ms-date" => datestamp,:"Content-Length" => "0", :"Content-Type" => "text/plain"}
316
316
  params = {:resource => "file", :recursive => "false"}
317
317
  auth_header = create_auth_header("put", datestamp, "#{@azure_container}#{blob_path}", headers, params)
318
318
  headers[:Authorization] = auth_header
@@ -333,13 +333,13 @@ module Fluent::Plugin
333
333
 
334
334
  private
335
335
  def append_blob_block(blob_path, content, position)
336
- log.debug "azurestorage_gen2: append_blob_block.start: Append blob ('#{blob_path}') called with position #{position}"
336
+ log.debug "azurestorage_gen2: append_blob_block.start: Append blob ('#{blob_path}') called with position #{position} (content length: #{content.length}, end position: #{position + content.length})"
337
337
  datestamp = create_request_date
338
- headers = {:"x-ms-version" => ABFS_API_VERSION, :"x-ms-date" => datestamp, :"x-ms-content-type" => "#{@blob_content_type}", :"Content-Length" => content.length}
338
+ headers = {:"x-ms-version" => ABFS_API_VERSION, :"x-ms-date" => datestamp, :"Content-Length" => content.length}
339
339
  params = {:action => "append", :position => "#{position}"}
340
340
  auth_header = create_auth_header("patch", datestamp, "#{@azure_container}#{blob_path}", headers, params)
341
341
  headers[:Authorization] = auth_header
342
- request = Typhoeus::Request.new("https://#{azure_storage_account}#{URL_DOMAIN_SUFFIX}/#{@azure_container}#{blob_path}", :method => :patch, :body => content, :params => params, :headers=> headers)
342
+ request = Typhoeus::Request.new("https://#{azure_storage_account}#{URL_DOMAIN_SUFFIX}/#{@azure_container}#{blob_path}", :method => :patch, :headers=> headers, :params => params, :body => content)
343
343
  request.on_complete do |response|
344
344
  if response.success?
345
345
  log.debug "azurestorage_gen2: Blob '#{blob_path}' has been appended, response code: #{response.code}"
@@ -371,7 +371,7 @@ module Fluent::Plugin
371
371
  elsif response.timed_out?
372
372
  raise Fluent::UnrecoverableError, "Bloub '#{blob_path}' flush request timed out."
373
373
  else
374
- raise Fluent::UnrecoverableError, "Blob flush request failed - code: #{response.code}, body: #{response.body}, headers: #{response.headers}"
374
+ raise_error "Blob flush request failed - code: #{response.code}, body: #{response.body}, headers: #{response.headers}"
375
375
  end
376
376
  end
377
377
  request.run
@@ -509,6 +509,15 @@ module Fluent::Plugin
509
509
  Time.now.strftime('%a, %e %b %y %H:%M:%S %Z')
510
510
  end
511
511
 
512
+ private
513
+ def raise_error(error_message)
514
+ if @enable_retry
515
+ raise BlobOperationError, error_message
516
+ else
517
+ raise Fluent::UnrecoverableError, error_message
518
+ end
519
+ end
520
+
512
521
  def uuid_random
513
522
  require 'uuidtools'
514
523
  ::UUIDTools::UUID.random_create.to_s
@@ -625,4 +634,10 @@ module Fluent::Plugin
625
634
  super(message)
626
635
  end
627
636
  end
637
+
638
+ class BlobOperationError < StandardError
639
+ def initialize(message="Default message")
640
+ super(message)
641
+ end
642
+ end
628
643
  end
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.1.4
4
+ version: 0.2.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: 2019-12-23 00:00:00.000000000 Z
11
+ date: 2020-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd