fluent-plugin-scalyr-threaded 1.0.8.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,37 @@
1
+ #
2
+ # Scalyr Output Plugin for Fluentd
3
+ #
4
+ # Copyright (C) 2015 Scalyr, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+
19
+ require 'fluent/test'
20
+ require 'fluent/plugin/out_scalyr'
21
+
22
+ module Scalyr
23
+ class ScalyrOutTest < Test::Unit::TestCase
24
+ def setup
25
+ Fluent::Test.setup
26
+ end
27
+
28
+ CONFIG = %[
29
+ api_write_token test_token
30
+ ssl_ca_bundle_path /etc/ssl/certs/ca-certificates.crt
31
+ ]
32
+
33
+ def create_driver( conf = CONFIG )
34
+ Fluent::Test::BufferedOutputTestDriver.new( Scalyr::ScalyrOut ).configure( conf )
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,72 @@
1
+ #
2
+ # Scalyr Output Plugin for Fluentd
3
+ #
4
+ # Copyright (C) 2015 Scalyr, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+
19
+ require 'helper'
20
+ require 'socket'
21
+
22
+ class ConfigTest < Scalyr::ScalyrOutTest
23
+
24
+ def test_default_params
25
+ d = create_driver
26
+ hostname = Socket.gethostname
27
+ assert_not_nil( d.instance.server_attributes, "Default server_attributes should not be nil" )
28
+ assert_equal( hostname, d.instance.server_attributes['serverHost'], "Default serverHost is not hostname" )
29
+ assert( d.instance.ssl_verify_peer, "Default ssl_verify_peer should be true" )
30
+
31
+ #check default buffer limits because they are set outside of the config_set_default
32
+ assert_equal( 100*1024, d.instance.buffer.buffer_chunk_limit, "Buffer chunk limit should be 100k" )
33
+ assert_equal( 1024, d.instance.buffer.buffer_queue_limit, "Buffer queue limit should be 1024" )
34
+ end
35
+
36
+ def test_custom_serverhost_not_overwritten
37
+ hostname = "customHost"
38
+ d = create_driver CONFIG + "server_attributes { \"serverHost\":\"#{hostname}\" }\nuse_hostname_for_serverhost true"
39
+ assert_equal( hostname, d.instance.server_attributes['serverHost'], "Custom serverHost should not be overwritten" )
40
+ end
41
+
42
+ def test_configure_use_hostname_for_serverhost
43
+ d = create_driver CONFIG + 'use_hostname_for_serverhost false'
44
+ assert_nil( d.instance.server_attributes, "Default server_attributes should be nil" )
45
+ end
46
+
47
+ def test_configure_ssl_verify_peer
48
+ d = create_driver CONFIG + 'ssl_verify_peer false'
49
+ assert( !d.instance.ssl_verify_peer, "Config failed to set ssl_verify_peer" )
50
+ end
51
+
52
+ def test_scalyr_server_adding_trailing_slash
53
+ d = create_driver CONFIG + 'scalyr_server http://www.example.com'
54
+ assert_equal( "http://www.example.com/", d.instance.scalyr_server, "Missing trailing slash for scalyr_server" )
55
+ end
56
+
57
+ def test_configure_ssl_ca_bundle_path
58
+ d = create_driver CONFIG + 'ssl_ca_bundle_path /test/ca-bundle.crt'
59
+ assert_equal( "/test/ca-bundle.crt", d.instance.ssl_ca_bundle_path, "Config failed to set ssl_ca_bundle_path" )
60
+ end
61
+
62
+ def test_configure_ssl_verify_depth
63
+ d = create_driver CONFIG + 'ssl_verify_depth 10'
64
+ assert_equal( 10, d.instance.ssl_verify_depth, "Config failed to set ssl_verify_depth" )
65
+ end
66
+
67
+ def test_configure_server_attributes
68
+ d = create_driver CONFIG + 'server_attributes { "test":"value" }'
69
+ assert_equal( "value", d.instance.server_attributes["test"], "Config failed to set server_attributes" )
70
+ end
71
+ end
72
+
@@ -0,0 +1,248 @@
1
+ #
2
+ # Scalyr Output Plugin for Fluentd
3
+ #
4
+ # Copyright (C) 2015 Scalyr, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+
19
+ require 'helper'
20
+ require 'fluent/event'
21
+
22
+ class EventsTest < Scalyr::ScalyrOutTest
23
+
24
+ def test_format
25
+ d = create_driver
26
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
27
+ mock = flexmock( d.instance )
28
+ mock.should_receive( :post_request ).with_any_args.and_return( response )
29
+
30
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
31
+ d.emit( { "a" => 1 }, time )
32
+ d.expect_format [ "test", time, { "a" => 1 } ].to_msgpack
33
+ d.run
34
+ end
35
+
36
+ def test_build_add_events_body_basic_values
37
+ d = create_driver
38
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
39
+ mock = flexmock( d.instance )
40
+
41
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
42
+ attrs = { "a" => 1 }
43
+ d.emit( attrs, time )
44
+
45
+ attrs["logfile"] = "/fluentd/test";
46
+
47
+ mock.should_receive( :post_request ).with(
48
+ URI,
49
+ on { |request_body|
50
+ body = JSON.parse( request_body )
51
+ assert( body.key?( "token" ), "Missing token field" )
52
+ assert( body.key?( "client_timestamp" ), "Missing client_timestamp field" )
53
+ assert( body.key?( "session" ), "Missing session field" )
54
+ assert( !body.key?( "sessionInfo"), "sessionInfo field set, but no sessionInfo" )
55
+ assert( body.key?( "events" ), "missing events field" )
56
+ assert( body.key?( "threads" ), "missing threads field" )
57
+ assert_equal( 1, body['events'].length, "Only expecting 1 event" )
58
+ assert_equal( d.instance.to_nanos( time ), body['events'][0]['ts'].to_i, "Event timestamp differs" )
59
+ assert_equal( attrs, body['events'][0]['attrs'], "Value of attrs differs from log" )
60
+ true
61
+ }
62
+ ).and_return( response )
63
+
64
+ d.run
65
+ end
66
+
67
+ def test_build_add_events_body_dont_override_logfile_field
68
+ d = create_driver
69
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
70
+ mock = flexmock( d.instance )
71
+
72
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
73
+ attrs = { "a" => 1 }
74
+ attrs["logfile"] = "/some/log/file";
75
+ d.emit( attrs, time )
76
+
77
+ mock.should_receive( :post_request ).with(
78
+ URI,
79
+ on { |request_body|
80
+ body = JSON.parse( request_body )
81
+ assert_equal( attrs, body['events'][0]['attrs'], "Value of attrs differs from log" )
82
+ true
83
+ }
84
+ ).and_return( response )
85
+
86
+ d.run
87
+ end
88
+
89
+ def test_build_add_events_body_with_server_attributes
90
+ d = create_driver CONFIG + 'server_attributes { "test":"value" }'
91
+
92
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
93
+ mock = flexmock( d.instance )
94
+
95
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
96
+ attrs = { "a" => 1 }
97
+ d.emit( attrs, time )
98
+
99
+ mock.should_receive( :post_request ).with(
100
+ URI,
101
+ on { |request_body|
102
+ body = JSON.parse( request_body )
103
+ assert( body.key?( "sessionInfo"), "sessionInfo field set, but no sessionInfo" )
104
+ assert_equal( "value", body["sessionInfo"]["test"] )
105
+ true
106
+ }
107
+ ).and_return( response )
108
+
109
+ d.run
110
+ end
111
+
112
+ def test_build_add_events_body_incrementing_timestamps
113
+ d = create_driver
114
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
115
+ mock = flexmock( d.instance )
116
+
117
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
118
+ d.emit( { "a" => 1 }, time )
119
+ d.emit( { "a" => 2 }, time )
120
+
121
+ time = Time.parse("2015-04-01 09:59:00 UTC").to_i
122
+ d.emit( { "a" => 3 }, time )
123
+
124
+ mock.should_receive( :post_request ).with(
125
+ URI,
126
+ on { |request_body|
127
+ body = JSON.parse( request_body )
128
+ events = body['events']
129
+ assert_equal( 3, events.length, "Expecting 3 events" )
130
+ #test equal timestamps are increased
131
+ assert events[1]['ts'].to_i > events[0]['ts'].to_i, "Event timestamps must increase"
132
+
133
+ #test earlier timestamps are increased
134
+ assert events[2]['ts'].to_i > events[1]['ts'].to_i, "Event timestamps must increase"
135
+
136
+ true
137
+ }
138
+ ).and_return( response )
139
+
140
+ d.run
141
+ end
142
+
143
+ def test_build_add_events_body_thread_ids
144
+ d = create_driver
145
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
146
+ mock = flexmock( d.instance )
147
+
148
+ entries = []
149
+
150
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
151
+ entries << [time, { "a" => 1 }]
152
+
153
+ es = Fluent::ArrayEventStream.new(entries)
154
+ buffer = d.instance.format_stream("test1", es)
155
+
156
+ chunk = d.instance.buffer.new_chunk('')
157
+ chunk << buffer
158
+
159
+ buffer = d.instance.format_stream("test2", es)
160
+ chunk << buffer
161
+
162
+ mock.should_receive( :post_request ).with(
163
+ URI,
164
+ on { |request_body|
165
+ body = JSON.parse( request_body )
166
+ events = body['events']
167
+ threads = body['threads']
168
+
169
+ assert_equal( 2, threads.length, "Expecting 2 threads, #{threads.length} found" )
170
+ assert_equal( 2, events.length, "Expecting 2 events, #{events.length} found" )
171
+ assert_equal( events[0]['thread'], threads[0]['id'].to_s, "thread id should match event thread id" )
172
+ assert_equal( events[1]['thread'], threads[1]['id'].to_s, "thread id should match event thread id" )
173
+ true
174
+ }
175
+ ).at_least.once.and_return( response )
176
+
177
+ d.instance.start
178
+ d.instance.write( chunk )
179
+ d.instance.shutdown
180
+ end
181
+
182
+ def test_default_message_field
183
+ d = create_driver CONFIG
184
+
185
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
186
+ mock = flexmock( d.instance )
187
+
188
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
189
+ attrs = { "log" => "this is a test", "logfile" => "/fluentd/test" }
190
+ d.emit( attrs, time )
191
+
192
+ mock.should_receive( :post_request ).with(
193
+ URI,
194
+ on { |request_body|
195
+ body = JSON.parse( request_body )
196
+ events = body['events']
197
+ assert_equal( attrs, body['events'][0]['attrs'], "Value of attrs differs from log" )
198
+ true
199
+ }
200
+ ).and_return( response )
201
+
202
+ d.run
203
+ end
204
+
205
+ def test_different_message_field
206
+ d = create_driver CONFIG + 'message_field log'
207
+
208
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
209
+ mock = flexmock( d.instance )
210
+
211
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
212
+ attrs = { "log" => "this is a test" }
213
+ d.emit( attrs, time )
214
+
215
+ mock.should_receive( :post_request ).with(
216
+ URI,
217
+ on { |request_body|
218
+ body = JSON.parse( request_body )
219
+ events = body['events']
220
+ assert( events[0]['attrs'].key?( 'message'), "'message' field not found in event" )
221
+ assert_equal( "this is a test", events[0]['attrs']['message'], "'message' field incorrect" )
222
+ assert( !events[0]['attrs'].key?( 'log' ), "'log' field should no longer exist in event" )
223
+ true
224
+ }
225
+ ).and_return( response )
226
+
227
+ d.run
228
+ end
229
+
230
+ def test_different_message_field_message_already_exists
231
+ d = create_driver CONFIG + 'message_field log'
232
+
233
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
234
+ mock = flexmock( d.instance )
235
+ mock.should_receive( :post_request ).and_return( response )
236
+
237
+ time = Time.parse("2015-04-01 10:00:00 UTC").to_i
238
+ attrs = { "log" => "this is a test", "message" => "uh oh" }
239
+ d.emit( attrs, time )
240
+
241
+ logger = flexmock( $log )
242
+ logger.should_receive( :warn ).with( /overwriting log record field 'message'/i ).at_least().once()
243
+
244
+ d.run
245
+ end
246
+
247
+ end
248
+
@@ -0,0 +1,90 @@
1
+ #
2
+ # Scalyr Output Plugin for Fluentd
3
+ #
4
+ # Copyright (C) 2015 Scalyr, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+
19
+ require 'helper'
20
+ require 'flexmock/test_unit'
21
+
22
+ class HandleResponseTest < Scalyr::ScalyrOutTest
23
+
24
+ def test_handle_response_missing_status
25
+ d = create_driver
26
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "message":"An invalid message" }' )
27
+ exception = assert_raise( Scalyr::ServerError, "Server error not raised for missing status" ) {
28
+ d.instance.handle_response( response )
29
+ }
30
+
31
+ assert_equal( "JSON response does not contain status message", exception.message )
32
+ end
33
+
34
+ def test_handle_response_discard_buffer
35
+ d = create_driver
36
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "message":"An invalid message", "status":"error/server/discardBuffer" }' )
37
+ logger = flexmock( $log )
38
+ logger.should_receive( :warn ).with( /buffer dropped/i )
39
+ assert_nothing_raised( Scalyr::ServerError, Scalyr::ClientError, "Nothing should be raised when discarding the buffer" ) {
40
+ d.instance.handle_response( response )
41
+ }
42
+
43
+ end
44
+
45
+ def test_handle_response_unknown_error
46
+ d = create_driver
47
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "message":"An invalid message", "status":"error/other" }' )
48
+ exception = assert_raise( Scalyr::ServerError, "Server error not raised for error status" ) {
49
+ d.instance.handle_response( response )
50
+ }
51
+ assert_equal( "error/other", exception.message )
52
+ end
53
+
54
+ def test_handle_response_client_error
55
+ d = create_driver
56
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "message":"An invalid message", "status":"error/client/test" }' )
57
+ exception = assert_raise( Scalyr::ClientError, "Client error not raised for error status" ) {
58
+ d.instance.handle_response( response )
59
+ }
60
+ assert_equal( "error/client/test", exception.message )
61
+ end
62
+
63
+ def test_handle_response_server_error
64
+ d = create_driver
65
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "message":"An invalid message", "status":"error/server/test" }' )
66
+ exception = assert_raise( Scalyr::ServerError, "Server error not raised for error status" ) {
67
+ d.instance.handle_response( response )
68
+ }
69
+ assert_equal( "error/server/test", exception.message )
70
+ end
71
+
72
+ def test_handle_response_code_4xx
73
+ d = create_driver
74
+ response = flexmock( Net::HTTPResponse, :code => '404', :body =>'{ "status":"error/server/fileNotFound" }' )
75
+ exception = assert_raise( Scalyr::Client4xxError, "No 4xx exception raised" ) {
76
+ d.instance.handle_response( response )
77
+ }
78
+ assert_equal( "error/server/fileNotFound", exception.message )
79
+ end
80
+
81
+ def test_handle_response_code_200
82
+ d = create_driver
83
+ response = flexmock( Net::HTTPResponse, :code => '200', :body =>'{ "status":"success" }' )
84
+ exception = assert_nothing_raised( Scalyr::ServerError, Scalyr::ClientError, "Error raised on success" ) {
85
+ d.instance.handle_response( response )
86
+ }
87
+ end
88
+
89
+ end
90
+