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 +4 -4
- data/README.md +1 -1
- data/lib/logstash/outputs/keystone/token.rb +3 -4
- data/lib/logstash/outputs/monasca/monasca_log_api_client.rb +13 -14
- data/lib/logstash/outputs/monasca_log_api.rb +28 -8
- data/logstash-output-monasca_log_api.gemspec +2 -2
- data/spec/outputs/monasca/monasca_log_api_client_spec.rb +22 -11
- data/spec/outputs/monasca_log_api_spec.rb +76 -12
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a68c60ae2810a248afe5944379274a1ebe442ac
|
4
|
+
data.tar.gz: 666e18514a756959708cf727373e21b415588a5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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(
|
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
|
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?
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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(
|
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(
|
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(
|
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 = {
|
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(
|
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]
|
203
|
+
if @logs[JSON_LOGS] && !@logs[JSON_LOGS].empty?
|
204
204
|
check_token
|
205
|
-
|
205
|
+
token = LogStash::Outputs::Keystone::Token.instance
|
206
206
|
@logger.debug("Sending #{@logs[JSON_LOGS].size} logs")
|
207
|
-
|
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
|
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.
|
4
|
-
s.licenses = ['Apache
|
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
|
-
|
107
|
-
'
|
108
|
-
'
|
109
|
-
'
|
110
|
-
|
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
|
120
|
-
it '
|
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
|
-
.
|
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
|
-
|
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) {
|
184
|
-
let (:old_token_id) {
|
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([{
|
378
|
-
|
379
|
-
|
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([{
|
394
|
-
|
395
|
-
|
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([{
|
410
|
-
|
411
|
-
|
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(
|
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.
|
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-
|
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
|
146
|
+
- Apache-2.0
|
147
147
|
metadata:
|
148
148
|
logstash_plugin: 'true'
|
149
149
|
logstash_group: output
|