logstash-output-monasca_log_api 0.5.1 → 0.5.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: 574bed4eaf7960e5e102494e439fe7433582f50e
4
- data.tar.gz: 3be5356921f6b101be710c2a7eaa057dad41a219
3
+ metadata.gz: 6a68c60ae2810a248afe5944379274a1ebe442ac
4
+ data.tar.gz: 666e18514a756959708cf727373e21b415588a5e
5
5
  SHA512:
6
- metadata.gz: 847120ddd6fc6a12c87ef8e8828fdfeb54e32e34d458735df35aad317d85b16fe9bf4b5c45f44fa632b8b04dc15047d4497301d5d8741a9405221954f9afb217
7
- data.tar.gz: e369ab34daa398a122bddc9e099ee2e1c782e2321f85441849ca5829c37aaf0af598de7007985bd990715e8c63206f4131759c680d972d9d4d5d8226fdbbefde
6
+ metadata.gz: 5ac12f96dc455cecebd155d49e37b11ed2b7732c30a4007cb7b9bfddf22e1a0bdb471ebdaa4c1d9515ca45cca7cef28225c2257d3321593145c0b6fca7c91960
7
+ data.tar.gz: c5c244d3443176affc74014bcd0003380347bfd514756cbf6bbb9ce1e7a7c7f77b8e8e5a730ea421cbd6cb1b4c70ee9a02de8dd7617d7824782198b692b534b1
data/README.md CHANGED
@@ -109,7 +109,7 @@ bin/plugin install --no-verify
109
109
  ```
110
110
 
111
111
  Verify installed plugins:
112
- With ``bin/plugin list`` you can check installed plugins. There should be ``logstash-output-monasca_log_api``.
112
+ With ``bin/plugin list --verbose`` you can check installed plugins. There should be ``logstash-output-monasca_log_api``.
113
113
 
114
114
  ## Start logstash output plugin
115
115
 
@@ -28,11 +28,11 @@ module LogStash::Outputs
28
28
  token = @keystone_client
29
29
  .authenticate(username, user_domain_name, password, project_name, project_domain_name)
30
30
  set_token(token[:token], token[:expires_at])
31
- @logger.info("New token requested")
31
+ @logger.info('New token requested')
32
32
  @logger.debug("token=#{@id}, expire_at=#{@expires_at}")
33
33
  end
34
34
 
35
- def set_token id, expires_at
35
+ def set_token(id, expires_at)
36
36
  @id = id
37
37
  @expires_at = expires_at
38
38
  end
@@ -49,12 +49,11 @@ module LogStash::Outputs
49
49
  def valid?
50
50
  token_valid = true
51
51
  now = DateTime.now + Rational(1, 1440)
52
- if @id.nil? or now >= @expires_at
52
+ if @id.nil? || now >= @expires_at
53
53
  token_valid = false
54
54
  end
55
55
  token_valid
56
56
  end
57
-
58
57
  end
59
58
  end
60
59
  end
@@ -23,7 +23,7 @@ module LogStash::Outputs
23
23
  module Monasca
24
24
  class MonascaLogApiClient
25
25
 
26
- def initialize(url, insecure=false)
26
+ def initialize(url, insecure = false)
27
27
  @logger = Cabin::Channel.get(LogStash)
28
28
  @uri = URI.parse(url)
29
29
  @http = Net::HTTP.new(@uri.host, @uri.port)
@@ -34,17 +34,12 @@ module LogStash::Outputs
34
34
  end
35
35
 
36
36
  def send_logs(logs, auth_token)
37
- begin
38
- post_header = {
39
- 'X-Auth-Token' => auth_token,
40
- 'Content-Type' => 'application/json',
41
- }
42
- response = request('/logs', post_header, logs.to_json)
43
- handle_response(response)
44
- rescue => e
45
- @logger.warn('Sending event to monasca-log-api threw exception',
46
- :exceptionew => e)
47
- end
37
+ post_header = {
38
+ 'X-Auth-Token' => auth_token,
39
+ 'Content-Type' => 'application/json',
40
+ }
41
+ response = request('/logs', post_header, logs.to_json)
42
+ handle_response(response)
48
43
  end
49
44
 
50
45
  private
@@ -56,16 +51,20 @@ module LogStash::Outputs
56
51
  @http.request(post_request)
57
52
  end
58
53
 
54
+ class InvalidTokenError < StandardError; end
55
+
59
56
  def handle_response(response)
60
57
  case response
61
58
  when Net::HTTPNoContent
62
- @logger.debug("Successfully sent logs")
59
+ @logger.debug('Successfully sent logs')
60
+ when Net::HTTPUnauthorized # HTTP code: 401
61
+ @logger.warn("Invalid token. Response=#{response}")
62
+ raise InvalidTokenError, "Invalid token. Response=#{response}"
63
63
  else
64
64
  # TODO: Handle logs which could not be sent
65
65
  @logger.error("Failed to send logs. Response=#{response}")
66
66
  end
67
67
  end
68
-
69
68
  end
70
69
  end
71
70
  end
@@ -102,7 +102,7 @@ class LogStash::Outputs::MonascaLogApi < LogStash::Outputs::Base
102
102
 
103
103
  # if new log would exceed the bytesize then send logs without the new log
104
104
  if @logs[JSON_LOGS] and (logs_bytesize + log_bytesize) > max_data_size_kb
105
- @logger.debug("bytesize reached. Sending logs")
105
+ @logger.debug('bytesize reached. Sending logs')
106
106
  @mutex.synchronize do
107
107
  send_logs
108
108
  add_log log
@@ -112,7 +112,7 @@ class LogStash::Outputs::MonascaLogApi < LogStash::Outputs::Base
112
112
  # if the new log would reach the maximum bytesize or the maximum allowed
113
113
  # number of sendable logs is reached
114
114
  elsif @logs[JSON_LOGS] and (@logs[JSON_LOGS].size + 1 >= num_of_logs)
115
- @logger.debug("bytesize or maximum number of logs reached. Sending logs")
115
+ @logger.debug('bytesize or maximum number of logs reached. Sending logs')
116
116
  @mutex.synchronize do
117
117
  add_log log
118
118
  send_logs
@@ -135,7 +135,7 @@ class LogStash::Outputs::MonascaLogApi < LogStash::Outputs::Base
135
135
  event.to_hash['dimensions']
136
136
  type = event.to_hash['type'] if event.to_hash['type']
137
137
 
138
- log = { "message" => message, "dimensions" => { "path" => path }}
138
+ log = { 'message' => message, 'dimensions' => { 'path' => path }}
139
139
  log[JSON_DIMS]['type'] = type if type
140
140
  if local_dims
141
141
  begin
@@ -178,7 +178,7 @@ class LogStash::Outputs::MonascaLogApi < LogStash::Outputs::Base
178
178
 
179
179
  if @logs[JSON_LOGS] and (@logs[JSON_LOGS].size > 0) and
180
180
  ((Time.now - @start_time) >= elapsed_time_sec)
181
- @logger.debug("Time elapsed. Sending logs")
181
+ @logger.debug('Time elapsed. Sending logs')
182
182
  @mutex.synchronize do
183
183
  send_logs
184
184
  end
@@ -200,17 +200,37 @@ class LogStash::Outputs::MonascaLogApi < LogStash::Outputs::Base
200
200
  end
201
201
 
202
202
  def send_logs
203
- if @logs[JSON_LOGS] and @logs[JSON_LOGS].size > 0
203
+ if @logs[JSON_LOGS] && !@logs[JSON_LOGS].empty?
204
204
  check_token
205
- token_id = LogStash::Outputs::Keystone::Token.instance.id
205
+ token = LogStash::Outputs::Keystone::Token.instance
206
206
  @logger.debug("Sending #{@logs[JSON_LOGS].size} logs")
207
- @monasca_log_api_client.send_logs(@logs, token_id)
207
+ retry_tries = 5
208
+ begin
209
+ tries ||= retry_tries
210
+ @monasca_log_api_client.send_logs(@logs, token.id)
211
+ rescue LogStash::Outputs::Monasca::MonascaLogApiClient::InvalidTokenError => e
212
+ tries -= 1
213
+ if tries > 0
214
+ @logger.info("Unauthorized: #{e}. Requesting new token.")
215
+ token.request_new_token(
216
+ username, user_domain_name, password,
217
+ project_name, project_domain_name
218
+ )
219
+ retry
220
+ else
221
+ @logger.error("Unauthorized: #{e}. Requesting new token failed "\
222
+ "after #{retry_tries} retries.")
223
+ end
224
+ rescue => e
225
+ @logger.error('Sending event to monasca-log-api threw exception',
226
+ :exceptionew => e)
227
+ end
208
228
  @logs.clear
209
229
  initialize_logs_object
210
230
  end
211
231
  end
212
232
 
213
- def add_log log
233
+ def add_log(log)
214
234
  @logs[JSON_LOGS].push(log)
215
235
  if @logs[JSON_LOGS].size == 1
216
236
  @start_time = Time.now
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-monasca_log_api'
3
- s.version = '0.5.1'
4
- s.licenses = ['Apache License 2.0']
3
+ s.version = '0.5.2'
4
+ s.licenses = ['Apache-2.0']
5
5
  s.summary = 'This gem is a logstash output plugin to connect via http to monasca-log-api.'
6
6
  s.description = 'This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program'
7
7
  s.authors = ['Fujitsu Enabling Software Technology GmbH']
@@ -102,12 +102,14 @@ describe LogStash::Outputs::Monasca::MonascaLogApiClient do
102
102
  expect_any_instance_of(Cabin::Channel).to receive(:error)
103
103
 
104
104
  stub_request(:post, monasca_log_api_url_post)
105
- .with(:headers => {
106
- 'Accept'=>'*/*',
107
- 'Content-Type'=>'application/json',
108
- 'User-Agent'=>'Ruby',
109
- 'X-Auth-Token'=>'f8cdafb7dce94444ad781a53ddaff693'})
110
- .to_return(:status => 401)
105
+ .with(:headers =>
106
+ {
107
+ 'Accept' => '*/*',
108
+ 'Content-Type' => 'application/json',
109
+ 'User-Agent' => 'Ruby',
110
+ 'X-Auth-Token' => 'f8cdafb7dce94444ad781a53ddaff693'
111
+ })
112
+ .to_return(:status => 410)
111
113
 
112
114
  client = LogStash::Outputs::Monasca::MonascaLogApiClient
113
115
  .new(monasca_log_api_url)
@@ -116,17 +118,26 @@ describe LogStash::Outputs::Monasca::MonascaLogApiClient do
116
118
  end
117
119
  end
118
120
 
119
- context 'when request throws an exception' do
120
- it 'rescued the exception and logs a failure' do
121
+ context 'when request failed with 401' do
122
+ it 'logs a warning and throw an exception' do
121
123
  expect_any_instance_of(Cabin::Channel).to receive(:warn)
122
124
 
123
125
  stub_request(:post, monasca_log_api_url_post)
124
- .to_raise(Errno::ECONNREFUSED)
126
+ .with(:headers =>
127
+ {
128
+ 'Accept' => '*/*',
129
+ 'Content-Type' => 'application/json',
130
+ 'User-Agent' => 'Ruby',
131
+ 'X-Auth-Token' => 'f8cdafb7dce94444ad781a53ddaff693'
132
+ })
133
+ .to_return(:status => 401)
125
134
 
126
135
  client = LogStash::Outputs::Monasca::MonascaLogApiClient
127
136
  .new(monasca_log_api_url)
128
- client.send_logs(logs, token)
137
+
138
+ expect { client.send_logs(logs, token) }.to raise_error(
139
+ LogStash::Outputs::Monasca::MonascaLogApiClient::InvalidTokenError
140
+ )
129
141
  end
130
142
  end
131
-
132
143
  end
@@ -108,6 +108,7 @@ describe 'outputs/monasca_log_api' do
108
108
  let (:password) { 'qweqwe' }
109
109
 
110
110
  let (:monasca_log_api_url) { 'http://192.168.10.4:5607/v3.0' }
111
+ let (:monasca_log_api_url_post) { monasca_log_api_url + "/logs" }
111
112
  let (:keystone_api_url) { 'http://192.168.10.5:5000/v3' }
112
113
 
113
114
  let (:complete_config) {
@@ -180,8 +181,8 @@ describe 'outputs/monasca_log_api' do
180
181
 
181
182
  let (:valid_date) { DateTime.now + Rational(5, 1440) }
182
183
  let (:expired_date) { DateTime.now - Rational(5, 1440) }
183
- let (:token_id) { "f8cdafb7dce94444ad781a53ddaff693" }
184
- let (:old_token_id) { "553ae6ea7d074f00a12750e4aa1dad50" }
184
+ let (:token_id) { 'f8cdafb7dce94444ad781a53ddaff693' }
185
+ let (:old_token_id) { '553ae6ea7d074f00a12750e4aa1dad50' }
185
186
 
186
187
  let (:valid_token) { {:token => token_id,
187
188
  :expires_at => valid_date } }
@@ -374,9 +375,11 @@ describe 'outputs/monasca_log_api' do
374
375
  monasca_log_api.multi_receive([event_without_dims])
375
376
 
376
377
  expect(monasca_log_api.instance_variable_get(:@logs)['logs'])
377
- .to eq([{"message"=>"A graceful shutdown.",
378
- "dimensions"=>{"path"=>"/opt/logstash-2.2.0/test.log",
379
- "type"=>"test-type"}}])
378
+ .to eq([{ 'message' => 'A graceful shutdown.',
379
+ 'dimensions' => {
380
+ 'path' => '/opt/logstash-2.2.0/test.log',
381
+ 'type' => 'test-type' }
382
+ }])
380
383
  end
381
384
 
382
385
  it 'with one dimensions' do
@@ -390,9 +393,12 @@ describe 'outputs/monasca_log_api' do
390
393
  monasca_log_api.multi_receive([event_with_one_dim])
391
394
 
392
395
  expect(monasca_log_api.instance_variable_get(:@logs)['logs'])
393
- .to eq([{"message"=>"A graceful shutdown.",
394
- "dimensions"=>{"path"=>"/opt/logstash-2.2.0/test.log",
395
- "type"=>"test-type", "service"=>"nova"}}])
396
+ .to eq([{ 'message' => 'A graceful shutdown.',
397
+ 'dimensions' => {
398
+ 'path' => '/opt/logstash-2.2.0/test.log',
399
+ 'type' => 'test-type',
400
+ 'service' => 'nova' }
401
+ }])
396
402
  end
397
403
 
398
404
  it 'with more dimensions' do
@@ -406,9 +412,30 @@ describe 'outputs/monasca_log_api' do
406
412
  monasca_log_api.multi_receive([event_with_more_dims])
407
413
 
408
414
  expect(monasca_log_api.instance_variable_get(:@logs)['logs'])
409
- .to eq([{"message"=>"A graceful shutdown.",
410
- "dimensions"=>{"path"=>"/opt/logstash-2.2.0/test.log",
411
- "type"=>"test-type", "service"=>"nova", "priority"=>"high"}}])
415
+ .to eq([{ 'message' => 'A graceful shutdown.',
416
+ 'dimensions' => {
417
+ 'path' => '/opt/logstash-2.2.0/test.log',
418
+ 'type' => 'test-type',
419
+ 'service' => 'nova',
420
+ 'priority' => 'high' }
421
+ }])
422
+ end
423
+ end
424
+
425
+ context 'when sending logs raise exception' do
426
+ it 'logs a failure' do
427
+ expect_any_instance_of(Cabin::Channel).to receive(:error)
428
+
429
+ monasca_log_api = LogStash::Outputs::MonascaLogApi.new(complete_config)
430
+ expect_any_instance_of(LogStash::Outputs::Monasca::MonascaLogApiClient)
431
+ .to receive(:send_logs)
432
+ .and_raise(Errno::ETIMEDOUT)
433
+ expect_any_instance_of(LogStash::Outputs::Keystone::KeystoneClient)
434
+ .to receive(:authenticate).and_return(valid_token)
435
+
436
+ monasca_log_api.register
437
+ monasca_log_api.multi_receive([event, event])
438
+ expect { monasca_log_api.multi_receive([event]) }.to_not raise_error
412
439
  end
413
440
  end
414
441
 
@@ -439,7 +466,8 @@ describe 'outputs/monasca_log_api' do
439
466
  expect_any_instance_of(LogStash::Outputs::Monasca::MonascaLogApiClient)
440
467
  .to receive(:send_logs)
441
468
  expect_any_instance_of(LogStash::Outputs::Keystone::KeystoneClient)
442
- .to receive(:authenticate).with(complete_config['username'],
469
+ .to receive(:authenticate).with(
470
+ complete_config['username'],
443
471
  complete_config['user_domain_name'],
444
472
  complete_config['password'],
445
473
  complete_config['project_name'],
@@ -452,6 +480,42 @@ describe 'outputs/monasca_log_api' do
452
480
  monasca_log_api.multi_receive([event, event, event])
453
481
  expect(LogStash::Outputs::Keystone::Token.instance.id).to eq(token_id)
454
482
  end
483
+
484
+ it 'if unauthorized, renew it' do
485
+ stub_request(:post, monasca_log_api_url_post)
486
+ .with(:headers =>
487
+ {
488
+ 'Accept' => '*/*',
489
+ 'Content-Type' => 'application/json',
490
+ 'User-Agent' => 'Ruby',
491
+ 'X-Auth-Token' => 'f8cdafb7dce94444ad781a53ddaff693'
492
+ })
493
+ .to_return(:status => 401)
494
+
495
+ expect_any_instance_of(LogStash::Outputs::Monasca::MonascaLogApiClient)
496
+ .to receive(:handle_response).exactly(5).times
497
+ .and_raise(
498
+ LogStash::Outputs::Monasca::MonascaLogApiClient::InvalidTokenError
499
+ )
500
+
501
+ expect_any_instance_of(LogStash::Outputs::Keystone::KeystoneClient)
502
+ .to receive(:authenticate).exactly(6).times
503
+ .with(
504
+ complete_config['username'],
505
+ complete_config['user_domain_name'],
506
+ complete_config['password'],
507
+ complete_config['project_name'],
508
+ complete_config['project_domain_name']
509
+ )
510
+ .and_return(expired_token, valid_token)
511
+
512
+ monasca_log_api = LogStash::Outputs::MonascaLogApi.new(complete_config)
513
+ allow(monasca_log_api).to receive(:start_time_check)
514
+ monasca_log_api.register
515
+ expect(LogStash::Outputs::Keystone::Token.instance.id).to eq(old_token_id)
516
+ monasca_log_api.multi_receive([event, event, event])
517
+ expect(LogStash::Outputs::Keystone::Token.instance.id).to eq(token_id)
518
+ end
455
519
  end
456
520
 
457
521
  context 'when stopping plugin' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-monasca_log_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fujitsu Enabling Software Technology GmbH
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-10 00:00:00.000000000 Z
11
+ date: 2016-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logstash-core
@@ -143,7 +143,7 @@ files:
143
143
  - spec/outputs/spec_helper.rb
144
144
  homepage: https://github.com/FujitsuEnablingSoftwareTechnologyGmbH/logstash-output-monasca_api
145
145
  licenses:
146
- - Apache License 2.0
146
+ - Apache-2.0
147
147
  metadata:
148
148
  logstash_plugin: 'true'
149
149
  logstash_group: output