fluent-plugin-google-cloud 0.6.6 → 0.6.7.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/fluent-plugin-google-cloud.gemspec +1 -1
- data/lib/fluent/plugin/out_google_cloud.rb +330 -236
- data/test/plugin/base_test.rb +407 -46
- data/test/plugin/constants.rb +152 -13
- data/test/plugin/test_out_google_cloud.rb +2 -0
- metadata +4 -4
data/test/plugin/base_test.rb
CHANGED
@@ -256,10 +256,10 @@ module BaseTest
|
|
256
256
|
'some_null_field' => nil)
|
257
257
|
d.run
|
258
258
|
end
|
259
|
-
verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
|
259
|
+
verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry, i|
|
260
260
|
fields = get_fields(entry['jsonPayload'])
|
261
261
|
assert_equal 4, fields.size, entry
|
262
|
-
|
262
|
+
verify_default_log_entry_text(get_string(fields['msg']), i, entry)
|
263
263
|
assert_equal 'test', get_string(fields['tag2']), entry
|
264
264
|
assert_equal 5000, get_number(fields['data']), entry
|
265
265
|
assert_equal null_value, fields['some_null_field'], entry
|
@@ -302,42 +302,143 @@ module BaseTest
|
|
302
302
|
end
|
303
303
|
end
|
304
304
|
|
305
|
-
def
|
305
|
+
def test_structured_payload_json_log_default_not_parsed_text
|
306
306
|
setup_gce_metadata_stubs
|
307
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
308
|
+
'"data": 5000, "some_null_field": null}'
|
307
309
|
setup_logging_stubs do
|
308
|
-
d = create_driver
|
309
|
-
json_string = '{"msg": "test log entry 0", "tag2": "test", "data": 5000}'
|
310
|
+
d = create_driver(APPLICATION_DEFAULT_CONFIG)
|
310
311
|
d.emit('message' => 'notJSON ' + json_string)
|
311
312
|
d.emit('message' => json_string)
|
312
|
-
d.emit('message' => "\t" + json_string)
|
313
|
-
d.
|
313
|
+
d.emit('message' => " \r\n \t" + json_string)
|
314
|
+
d.run
|
315
|
+
end
|
316
|
+
verify_log_entries(3, COMPUTE_PARAMS, 'textPayload') do
|
317
|
+
# Only check for the existence of textPayload.
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def test_structured_payload_json_log_default_not_parsed_json
|
322
|
+
setup_gce_metadata_stubs
|
323
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
324
|
+
'"data": 5000, "some_null_field": null}'
|
325
|
+
setup_logging_stubs do
|
326
|
+
d = create_driver(APPLICATION_DEFAULT_CONFIG)
|
327
|
+
%w(log msg).each do |field|
|
328
|
+
d.emit(field => 'notJSON ' + json_string)
|
329
|
+
d.emit(field => json_string)
|
330
|
+
d.emit(field => " \r\n \t" + json_string)
|
331
|
+
end
|
332
|
+
d.run
|
333
|
+
end
|
334
|
+
verify_log_entries(6, COMPUTE_PARAMS, 'jsonPayload') do |entry|
|
335
|
+
fields = get_fields(entry['jsonPayload'])
|
336
|
+
assert !fields.key?('tag2'), 'Did not expect tag2'
|
337
|
+
assert !fields.key?('data'), 'Did not expect data'
|
338
|
+
assert !fields.key?('some_null_field'), 'Did not expect some_null_field'
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def test_structured_payload_json_log_detect_json_not_parsed_text
|
343
|
+
setup_gce_metadata_stubs
|
344
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
345
|
+
'"data": 5000, "some_null_field": null}'
|
346
|
+
setup_logging_stubs do
|
347
|
+
d = create_driver(DETECT_JSON_CONFIG)
|
348
|
+
d.emit('message' => 'notJSON ' + json_string)
|
314
349
|
d.run
|
315
350
|
end
|
316
|
-
verify_log_entries(
|
317
|
-
|
351
|
+
verify_log_entries(1, COMPUTE_PARAMS, 'textPayload') do
|
352
|
+
# Only check for the existence of textPayload.
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_structured_payload_json_log_detect_json_not_parsed_json
|
357
|
+
setup_gce_metadata_stubs
|
358
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
359
|
+
'"data": 5000, "some_null_field": null}'
|
360
|
+
setup_logging_stubs do
|
361
|
+
d = create_driver(DETECT_JSON_CONFIG)
|
362
|
+
%w(log msg).each do |field|
|
363
|
+
d.emit(field => 'notJSON ' + json_string)
|
364
|
+
end
|
365
|
+
d.run
|
366
|
+
end
|
367
|
+
verify_log_entries(2, COMPUTE_PARAMS, 'jsonPayload') do |entry|
|
368
|
+
fields = get_fields(entry['jsonPayload'])
|
369
|
+
assert !fields.key?('tag2'), 'Did not expect tag2'
|
370
|
+
assert !fields.key?('data'), 'Did not expect data'
|
371
|
+
assert !fields.key?('some_null_field'), 'Did not expect some_null_field'
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_structured_payload_json_log_detect_json_parsed
|
376
|
+
setup_gce_metadata_stubs
|
377
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
378
|
+
'"data": 5000, "some_null_field": null}'
|
379
|
+
setup_logging_stubs do
|
380
|
+
d = create_driver(DETECT_JSON_CONFIG)
|
381
|
+
%w(message log msg).each do |field|
|
382
|
+
d.emit(field => json_string)
|
383
|
+
d.emit(field => " \r\n \t" + json_string)
|
384
|
+
end
|
385
|
+
d.run
|
386
|
+
end
|
387
|
+
verify_log_entries(6, COMPUTE_PARAMS, 'jsonPayload') do |entry|
|
388
|
+
fields = get_fields(entry['jsonPayload'])
|
389
|
+
assert_equal 4, fields.size, entry
|
390
|
+
assert_equal 'test log entry 0', get_string(fields['msg']), entry
|
391
|
+
assert_equal 'test', get_string(fields['tag2']), entry
|
392
|
+
assert_equal 5000, get_number(fields['data']), entry
|
393
|
+
assert_equal null_value, fields['some_null_field'], entry
|
318
394
|
end
|
319
395
|
end
|
320
396
|
|
321
|
-
def
|
397
|
+
def test_structured_payload_json_log_default_container_not_parsed
|
322
398
|
setup_gce_metadata_stubs
|
323
399
|
setup_container_metadata_stubs
|
400
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
401
|
+
'"data": 5000, "some_null_field": null}'
|
324
402
|
setup_logging_stubs do
|
325
403
|
d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
|
326
|
-
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
327
|
-
'"data": 5000, "some_null_field": null}'
|
328
404
|
d.emit(container_log_entry_with_metadata('notJSON' + json_string))
|
329
405
|
d.emit(container_log_entry_with_metadata(json_string))
|
330
406
|
d.emit(container_log_entry_with_metadata(" \r\n \t" + json_string))
|
331
407
|
d.run
|
332
408
|
end
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
409
|
+
verify_log_entries(3, CONTAINER_FROM_METADATA_PARAMS, 'textPayload') do
|
410
|
+
# Only check for the existence of textPayload.
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
def test_structured_payload_json_log_detect_json_container_not_parsed
|
415
|
+
setup_gce_metadata_stubs
|
416
|
+
setup_container_metadata_stubs
|
417
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
418
|
+
'"data": 5000, "some_null_field": null}'
|
419
|
+
setup_logging_stubs do
|
420
|
+
d = create_driver(DETECT_JSON_CONFIG, CONTAINER_TAG)
|
421
|
+
d.emit(container_log_entry_with_metadata('notJSON' + json_string))
|
422
|
+
d.run
|
423
|
+
end
|
424
|
+
verify_log_entries(1, CONTAINER_FROM_METADATA_PARAMS, 'textPayload') do
|
425
|
+
# Only check for the existence of textPayload.
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def test_structured_payload_json_log_detect_json_container_parsed
|
430
|
+
setup_gce_metadata_stubs
|
431
|
+
setup_container_metadata_stubs
|
432
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
433
|
+
'"data": 5000, "some_null_field": null}'
|
434
|
+
setup_logging_stubs do
|
435
|
+
d = create_driver(DETECT_JSON_CONFIG, CONTAINER_TAG)
|
436
|
+
d.emit(container_log_entry_with_metadata(json_string))
|
437
|
+
d.emit(container_log_entry_with_metadata(" \r\n \t" + json_string))
|
438
|
+
d.run
|
439
|
+
end
|
440
|
+
verify_log_entries(2, CONTAINER_FROM_METADATA_PARAMS, 'jsonPayload') \
|
441
|
+
do |entry|
|
341
442
|
fields = get_fields(entry['jsonPayload'])
|
342
443
|
assert_equal 4, fields.size, entry
|
343
444
|
assert_equal 'test log entry 0', get_string(fields['msg']), entry
|
@@ -345,7 +446,6 @@ module BaseTest
|
|
345
446
|
assert_equal 5000, get_number(fields['data']), entry
|
346
447
|
assert_equal null_value, fields['some_null_field'], entry
|
347
448
|
end
|
348
|
-
end
|
349
449
|
end
|
350
450
|
|
351
451
|
# Verify that we drop the log entries when 'require_valid_tags' is true and
|
@@ -403,7 +503,7 @@ module BaseTest
|
|
403
503
|
end
|
404
504
|
params = CONTAINER_FROM_METADATA_PARAMS.merge(
|
405
505
|
labels: CONTAINER_FROM_METADATA_PARAMS[:labels].merge(
|
406
|
-
"#{
|
506
|
+
"#{GKE_CONSTANTS[:service]}/container_name" =>
|
407
507
|
URI.decode(encoded_name)),
|
408
508
|
log_name: encoded_name)
|
409
509
|
verify_log_entries(0, params, 'textPayload')
|
@@ -525,7 +625,8 @@ module BaseTest
|
|
525
625
|
end
|
526
626
|
end
|
527
627
|
verify_index = 0
|
528
|
-
verify_log_entries(emit_index, COMPUTE_PARAMS) do |entry|
|
628
|
+
verify_log_entries(emit_index, COMPUTE_PARAMS) do |entry, i|
|
629
|
+
verify_default_log_entry_text(entry['textPayload'], i, entry)
|
529
630
|
assert_equal_with_default entry['timestamp']['seconds'],
|
530
631
|
expected_ts[verify_index].tv_sec, 0, entry
|
531
632
|
assert_equal_with_default entry['timestamp']['nanos'],
|
@@ -643,10 +744,10 @@ module BaseTest
|
|
643
744
|
params[:labels]['sent_label_1'] = 'value1'
|
644
745
|
params[:labels]['foo.googleapis.com/bar'] = 'value2'
|
645
746
|
params[:labels]['label3'] = 'value3'
|
646
|
-
verify_log_entries(1, params, 'jsonPayload') do |entry|
|
747
|
+
verify_log_entries(1, params, 'jsonPayload') do |entry, i|
|
647
748
|
fields = get_fields(entry['jsonPayload'])
|
648
749
|
assert_equal 2, fields.size, entry
|
649
|
-
|
750
|
+
verify_default_log_entry_text(get_string(fields['message']), i, entry)
|
650
751
|
assert_equal 'value4', get_string(fields['not_a_label']), entry
|
651
752
|
end
|
652
753
|
end
|
@@ -729,9 +830,10 @@ module BaseTest
|
|
729
830
|
d.run
|
730
831
|
end
|
731
832
|
expected_params = CONTAINER_FROM_TAG_PARAMS.merge(
|
732
|
-
labels: { "#{
|
833
|
+
labels: { "#{GKE_CONSTANTS[:service]}/stream" => 'stderr' }
|
733
834
|
) { |_, oldval, newval| oldval.merge(newval) }
|
734
|
-
verify_log_entries(1, expected_params) do |entry|
|
835
|
+
verify_log_entries(1, expected_params) do |entry, i|
|
836
|
+
verify_default_log_entry_text(entry['textPayload'], i, entry)
|
735
837
|
assert_equal CONTAINER_SECONDS_EPOCH, entry['timestamp']['seconds'], entry
|
736
838
|
assert_equal CONTAINER_NANOS, entry['timestamp']['nanos'], entry
|
737
839
|
assert_equal 'ERROR', entry['severity'], entry
|
@@ -742,7 +844,7 @@ module BaseTest
|
|
742
844
|
setup_gce_metadata_stubs
|
743
845
|
setup_container_metadata_stubs
|
744
846
|
setup_logging_stubs do
|
745
|
-
d = create_driver(
|
847
|
+
d = create_driver(DETECT_JSON_CONFIG, CONTAINER_TAG)
|
746
848
|
d.emit(container_log_entry_with_metadata('{"msg": "test log entry 0", ' \
|
747
849
|
'"tag2": "test", "data": ' \
|
748
850
|
'5000, "severity": "WARNING"}'))
|
@@ -765,7 +867,7 @@ module BaseTest
|
|
765
867
|
setup_gce_metadata_stubs
|
766
868
|
setup_container_metadata_stubs
|
767
869
|
setup_logging_stubs do
|
768
|
-
d = create_driver(
|
870
|
+
d = create_driver(DETECT_JSON_CONFIG, CONTAINER_TAG)
|
769
871
|
d.emit(container_log_entry('{"msg": "test log entry 0", ' \
|
770
872
|
'"tag2": "test", "data": 5000, ' \
|
771
873
|
'"severity": "W"}'))
|
@@ -797,7 +899,8 @@ module BaseTest
|
|
797
899
|
n.times { |i| d.emit(cloudfunctions_log_entry(i)) }
|
798
900
|
d.run
|
799
901
|
end
|
800
|
-
verify_log_entries(n, CLOUDFUNCTIONS_PARAMS) do |entry|
|
902
|
+
verify_log_entries(n, CLOUDFUNCTIONS_PARAMS) do |entry, i|
|
903
|
+
verify_default_log_entry_text(entry['textPayload'], i, entry)
|
801
904
|
assert_equal 'DEBUG', entry['severity'],
|
802
905
|
"Test with #{n} logs failed. \n#{entry}"
|
803
906
|
end
|
@@ -838,13 +941,12 @@ module BaseTest
|
|
838
941
|
n.times { |i| d.emit(cloudfunctions_log_entry(i)) }
|
839
942
|
d.run
|
840
943
|
end
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
end
|
944
|
+
verify_log_entries(n, CONTAINER_FROM_TAG_PARAMS, 'textPayload') \
|
945
|
+
do |entry, i|
|
946
|
+
assert_equal '[D][2015-09-25T12:34:56.789Z][123-0] test log entry ' \
|
947
|
+
"#{i}", entry['textPayload'],
|
948
|
+
"Test with #{n} logs failed. \n#{entry}"
|
949
|
+
end
|
848
950
|
end
|
849
951
|
end
|
850
952
|
|
@@ -1004,6 +1106,197 @@ module BaseTest
|
|
1004
1106
|
end
|
1005
1107
|
end
|
1006
1108
|
|
1109
|
+
# Metadata Agent related tests.
|
1110
|
+
|
1111
|
+
# Test enable_metadata_agent not set or set to false.
|
1112
|
+
def test_configure_enable_metadata_agent_default_and_false
|
1113
|
+
setup_gce_metadata_stubs
|
1114
|
+
[create_driver, create_driver(DISABLE_METADATA_AGENT_CONFIG)].each do |d|
|
1115
|
+
assert_false d.instance.instance_variable_get(:@enable_metadata_agent)
|
1116
|
+
end
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
# Test enable_metadata_agent set to true.
|
1120
|
+
def test_configure_enable_metadata_agent_true
|
1121
|
+
new_stub_context do
|
1122
|
+
setup_gce_metadata_stubs
|
1123
|
+
setup_metadata_agent_stubs
|
1124
|
+
d = create_driver(ENABLE_METADATA_AGENT_CONFIG)
|
1125
|
+
assert_true d.instance.instance_variable_get(:@enable_metadata_agent)
|
1126
|
+
assert_requested_metadata_agent_stub(IMPLICIT_LOCAL_RESOURCE_ID)
|
1127
|
+
end
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
# Test that an implicit monitored resource can be retrieved from Metadata
|
1131
|
+
# Agent with an empty string as the local_resource_id.
|
1132
|
+
def test_retrieve_implicit_monitored_resource
|
1133
|
+
# GCE metadata stubs has VM_ID and ZONE, while the Metadata Agent stub has
|
1134
|
+
# METADATA_VM_ID and METADATA_ZONE.
|
1135
|
+
new_stub_context do
|
1136
|
+
setup_gce_metadata_stubs
|
1137
|
+
setup_metadata_agent_stubs
|
1138
|
+
setup_logging_stubs do
|
1139
|
+
d = create_driver(ENABLE_METADATA_AGENT_CONFIG)
|
1140
|
+
d.emit('message' => log_entry(0))
|
1141
|
+
d.run
|
1142
|
+
end
|
1143
|
+
verify_log_entries(1, COMPUTE_PARAMS_WITH_METADATA_VM_ID_AND_ZONE)
|
1144
|
+
assert_requested_metadata_agent_stub(IMPLICIT_LOCAL_RESOURCE_ID)
|
1145
|
+
end
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
# Docker Container.
|
1149
|
+
|
1150
|
+
# Test textPayload logs from Docker container stdout / stderr.
|
1151
|
+
def test_docker_container_stdout_stderr_logs_text_payload
|
1152
|
+
[1, 2, 3, 5, 11, 50].each do |n|
|
1153
|
+
new_stub_context do
|
1154
|
+
setup_gce_metadata_stubs
|
1155
|
+
setup_metadata_agent_stubs
|
1156
|
+
setup_logging_stubs do
|
1157
|
+
d = create_driver(DOCKER_CONTAINER_CONFIG)
|
1158
|
+
n.times do |i|
|
1159
|
+
d.emit(docker_container_stdout_stderr_log_entry(log_entry(i)))
|
1160
|
+
end
|
1161
|
+
d.run
|
1162
|
+
end
|
1163
|
+
verify_log_entries(n, DOCKER_CONTAINER_PARAMS)
|
1164
|
+
assert_requested_metadata_agent_stub(IMPLICIT_LOCAL_RESOURCE_ID)
|
1165
|
+
assert_requested_metadata_agent_stub("container.#{DOCKER_CONTAINER_ID}")
|
1166
|
+
end
|
1167
|
+
end
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
# Test jsonPayload logs from Docker container stdout / stderr.
|
1171
|
+
def test_docker_container_stdout_stderr_logs_json_payload
|
1172
|
+
[1, 2, 3, 5, 11, 50].each do |n|
|
1173
|
+
new_stub_context do
|
1174
|
+
setup_gce_metadata_stubs
|
1175
|
+
setup_metadata_agent_stubs
|
1176
|
+
setup_logging_stubs do
|
1177
|
+
d = create_driver(DOCKER_CONTAINER_CONFIG)
|
1178
|
+
n.times do
|
1179
|
+
d.emit(docker_container_stdout_stderr_log_entry(
|
1180
|
+
'{"msg": "test log entry ' \
|
1181
|
+
"#{n}" \
|
1182
|
+
'", "tag2": "test", "data": ' \
|
1183
|
+
'5000, "severity": "WARNING"}'))
|
1184
|
+
end
|
1185
|
+
d.run
|
1186
|
+
end
|
1187
|
+
verify_log_entries(n, DOCKER_CONTAINER_PARAMS, 'jsonPayload') do |entry|
|
1188
|
+
fields = get_fields(entry['jsonPayload'])
|
1189
|
+
assert_equal 3, fields.size, entry
|
1190
|
+
assert_equal "test log entry #{n}", get_string(fields['msg']), entry
|
1191
|
+
assert_equal 'test', get_string(fields['tag2']), entry
|
1192
|
+
assert_equal 5000, get_number(fields['data']), entry
|
1193
|
+
end
|
1194
|
+
assert_requested_metadata_agent_stub(IMPLICIT_LOCAL_RESOURCE_ID)
|
1195
|
+
assert_requested_metadata_agent_stub("container.#{DOCKER_CONTAINER_ID}")
|
1196
|
+
end
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
# Test logs from applications running in Docker containers. These logs have
|
1201
|
+
# the label "logging.googleapis.com/local_resource_id" set in the format of
|
1202
|
+
# "containerName.<container_name>".
|
1203
|
+
def test_docker_container_application_logs
|
1204
|
+
new_stub_context do
|
1205
|
+
setup_gce_metadata_stubs
|
1206
|
+
setup_metadata_agent_stubs
|
1207
|
+
setup_logging_stubs do
|
1208
|
+
# Metadata Agent is not enabled. Will call Docker Remote API for
|
1209
|
+
# container info.
|
1210
|
+
d = create_driver(ENABLE_METADATA_AGENT_CONFIG)
|
1211
|
+
d.emit(docker_container_application_log_entry(log_entry(0)))
|
1212
|
+
d.run
|
1213
|
+
end
|
1214
|
+
verify_log_entries(1, DOCKER_CONTAINER_PARAMS_WITH_NO_STREAM)
|
1215
|
+
assert_requested_metadata_agent_stub(IMPLICIT_LOCAL_RESOURCE_ID)
|
1216
|
+
assert_requested_metadata_agent_stub(
|
1217
|
+
"containerName.#{DOCKER_CONTAINER_NAME}")
|
1218
|
+
end
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
# Test that the 'time' field from the json record is extracted and set to
|
1222
|
+
# entry.timestamp for Docker container logs.
|
1223
|
+
def test_time_field_extraction_for_docker_container_logs
|
1224
|
+
new_stub_context do
|
1225
|
+
setup_gce_metadata_stubs
|
1226
|
+
setup_metadata_agent_stubs
|
1227
|
+
setup_logging_stubs do
|
1228
|
+
d = create_driver(ENABLE_METADATA_AGENT_CONFIG)
|
1229
|
+
d.emit(docker_container_application_log_entry(log_entry(0)))
|
1230
|
+
d.run
|
1231
|
+
end
|
1232
|
+
verify_log_entries(1, DOCKER_CONTAINER_PARAMS_WITH_NO_STREAM) do |entry|
|
1233
|
+
# Timestamp in 'time' field from log entry should be set properly.
|
1234
|
+
assert_equal DOCKER_CONTAINER_SECONDS_EPOCH,
|
1235
|
+
entry['timestamp']['seconds'], entry
|
1236
|
+
assert_equal DOCKER_CONTAINER_NANOS,
|
1237
|
+
entry['timestamp']['nanos'], entry
|
1238
|
+
end
|
1239
|
+
assert_requested_metadata_agent_stub(IMPLICIT_LOCAL_RESOURCE_ID)
|
1240
|
+
assert_requested_metadata_agent_stub(
|
1241
|
+
"containerName.#{DOCKER_CONTAINER_NAME}")
|
1242
|
+
end
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
# Test that the 'source' field is properly extracted from the record json and
|
1246
|
+
# set as a common label 'stream'. Also entry.severity is set accordingly for
|
1247
|
+
# Docker container logs.
|
1248
|
+
def test_source_and_severity_for_docker_container_logs
|
1249
|
+
{
|
1250
|
+
docker_container_stdout_stderr_log_entry(
|
1251
|
+
log_entry(0), DOCKER_CONTAINER_STREAM_STDOUT) =>
|
1252
|
+
DOCKER_CONTAINER_PARAMS,
|
1253
|
+
docker_container_stdout_stderr_log_entry(
|
1254
|
+
log_entry(0), DOCKER_CONTAINER_STREAM_STDERR) =>
|
1255
|
+
DOCKER_CONTAINER_PARAMS_WITH_STREAM_STDERR,
|
1256
|
+
docker_container_application_log_entry(log_entry(0)) =>
|
1257
|
+
DOCKER_CONTAINER_PARAMS_WITH_NO_STREAM,
|
1258
|
+
docker_container_application_log_entry(log_entry(0)) \
|
1259
|
+
.merge('severity' => 'warning') =>
|
1260
|
+
DOCKER_CONTAINER_PARAMS_WITH_NO_STREAM
|
1261
|
+
}.each do |log_entry, expected_params|
|
1262
|
+
new_stub_context do
|
1263
|
+
setup_gce_metadata_stubs
|
1264
|
+
setup_metadata_agent_stubs
|
1265
|
+
setup_logging_stubs do
|
1266
|
+
d = create_driver(DOCKER_CONTAINER_CONFIG)
|
1267
|
+
d.emit(log_entry)
|
1268
|
+
d.run
|
1269
|
+
end
|
1270
|
+
verify_log_entries(1, expected_params)
|
1271
|
+
end
|
1272
|
+
end
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
# Test GKE container logs. These logs have the label
|
1276
|
+
# "logging.googleapis.com/local_resource_id" set in the format of
|
1277
|
+
# "gke_containerName.<namespace_id>.<pod_name>.<container_name>".
|
1278
|
+
def test_gke_container_logs
|
1279
|
+
[1, 2, 3, 5, 11, 50].each do |n|
|
1280
|
+
new_stub_context do
|
1281
|
+
setup_gce_metadata_stubs
|
1282
|
+
setup_container_metadata_stubs
|
1283
|
+
setup_metadata_agent_stubs
|
1284
|
+
setup_logging_stubs do
|
1285
|
+
d = create_driver(ENABLE_METADATA_AGENT_CONFIG)
|
1286
|
+
n.times do |i|
|
1287
|
+
d.emit(gke_container_log_entry(log_entry(i)))
|
1288
|
+
end
|
1289
|
+
d.run
|
1290
|
+
end
|
1291
|
+
verify_log_entries(n, CONTAINER_FROM_APPLICATION_PARAMS)
|
1292
|
+
assert_requested_metadata_agent_stub(IMPLICIT_LOCAL_RESOURCE_ID)
|
1293
|
+
assert_requested_metadata_agent_stub(
|
1294
|
+
"gke_containerName.#{CONTAINER_NAMESPACE_ID}.#{CONTAINER_POD_NAME}." \
|
1295
|
+
"#{CONTAINER_CONTAINER_NAME}")
|
1296
|
+
end
|
1297
|
+
end
|
1298
|
+
end
|
1299
|
+
|
1007
1300
|
private
|
1008
1301
|
|
1009
1302
|
def stub_metadata_request(metadata_path, response_body)
|
@@ -1119,6 +1412,33 @@ module BaseTest
|
|
1119
1412
|
Prometheus::Client.registry.instance_variable_set('@metrics', {})
|
1120
1413
|
end
|
1121
1414
|
|
1415
|
+
# Metadata Agent.
|
1416
|
+
|
1417
|
+
def metadata_request_url(local_resource_id)
|
1418
|
+
"#{DEFAULT_METADATA_AGENT_URL}/monitoredResource/#{local_resource_id}"
|
1419
|
+
end
|
1420
|
+
|
1421
|
+
# Provide a stub context that initializes @logs_sent, executes the block and
|
1422
|
+
# resets WebMock at the end.
|
1423
|
+
def new_stub_context
|
1424
|
+
@logs_sent = []
|
1425
|
+
yield
|
1426
|
+
WebMock.reset!
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
def setup_metadata_agent_stubs
|
1430
|
+
MONITORED_RESOURCE_STUBS.each do |local_resource_id, resource|
|
1431
|
+
stub_request(:get, metadata_request_url(local_resource_id))
|
1432
|
+
.to_return(status: 200, body: resource)
|
1433
|
+
end
|
1434
|
+
end
|
1435
|
+
|
1436
|
+
def assert_requested_metadata_agent_stub(local_resource_id)
|
1437
|
+
assert_requested :get, metadata_request_url(local_resource_id)
|
1438
|
+
end
|
1439
|
+
|
1440
|
+
# GKE Container.
|
1441
|
+
|
1122
1442
|
def container_tag_with_container_name(container_name)
|
1123
1443
|
"kubernetes.#{CONTAINER_POD_NAME}_#{CONTAINER_NAMESPACE_NAME}_" \
|
1124
1444
|
"#{container_name}"
|
@@ -1151,6 +1471,40 @@ module BaseTest
|
|
1151
1471
|
}
|
1152
1472
|
end
|
1153
1473
|
|
1474
|
+
def gke_container_log_entry(log)
|
1475
|
+
{
|
1476
|
+
log: log,
|
1477
|
+
LOCAL_RESOURCE_ID_KEY =>
|
1478
|
+
"gke_containerName.#{CONTAINER_NAMESPACE_ID}" \
|
1479
|
+
".#{CONTAINER_POD_NAME}.#{CONTAINER_CONTAINER_NAME}"
|
1480
|
+
}
|
1481
|
+
end
|
1482
|
+
|
1483
|
+
# Docker Container.
|
1484
|
+
|
1485
|
+
def docker_container_stdout_stderr_log_entry(
|
1486
|
+
log, stream = DOCKER_CONTAINER_STREAM_STDOUT)
|
1487
|
+
severity = if stream == DOCKER_CONTAINER_STREAM_STDOUT
|
1488
|
+
'INFO'
|
1489
|
+
else
|
1490
|
+
'ERROR'
|
1491
|
+
end
|
1492
|
+
{
|
1493
|
+
log: log,
|
1494
|
+
source: stream,
|
1495
|
+
severity: severity,
|
1496
|
+
LOCAL_RESOURCE_ID_KEY => "container.#{DOCKER_CONTAINER_ID}"
|
1497
|
+
}
|
1498
|
+
end
|
1499
|
+
|
1500
|
+
def docker_container_application_log_entry(log)
|
1501
|
+
{
|
1502
|
+
log: log,
|
1503
|
+
time: DOCKER_CONTAINER_TIMESTAMP,
|
1504
|
+
LOCAL_RESOURCE_ID_KEY => "containerName.#{DOCKER_CONTAINER_NAME}"
|
1505
|
+
}
|
1506
|
+
end
|
1507
|
+
|
1154
1508
|
def cloudfunctions_log_entry(i)
|
1155
1509
|
{
|
1156
1510
|
stream: 'stdout',
|
@@ -1189,7 +1543,7 @@ module BaseTest
|
|
1189
1543
|
end
|
1190
1544
|
|
1191
1545
|
def log_entry(i)
|
1192
|
-
|
1546
|
+
"test log entry #{i}"
|
1193
1547
|
end
|
1194
1548
|
|
1195
1549
|
def check_labels(labels, expected_labels)
|
@@ -1205,18 +1559,19 @@ module BaseTest
|
|
1205
1559
|
"#{labels.length} labels: #{labels}"
|
1206
1560
|
end
|
1207
1561
|
|
1562
|
+
def verify_default_log_entry_text(text, i, entry)
|
1563
|
+
assert_equal "test log entry #{i}", text,
|
1564
|
+
"Entry ##{i} had unexpected text: #{entry}"
|
1565
|
+
end
|
1566
|
+
|
1208
1567
|
# The caller can optionally provide a block which is called for each entry.
|
1209
1568
|
def verify_json_log_entries(n, params, payload_type = 'textPayload')
|
1210
1569
|
i = 0
|
1211
1570
|
@logs_sent.each do |request|
|
1212
1571
|
request['entries'].each do |entry|
|
1213
1572
|
unless payload_type.empty?
|
1214
|
-
assert entry.key?(payload_type),
|
1215
|
-
"#{payload_type} key: "
|
1216
|
-
# Check the payload for textPayload, otherwise it's up to the caller.
|
1217
|
-
if payload_type == 'textPayload'
|
1218
|
-
assert_equal "test log entry #{i}", entry['textPayload'], request
|
1219
|
-
end
|
1573
|
+
assert entry.key?(payload_type), "Entry ##{i} did not contain " \
|
1574
|
+
"expected #{payload_type} key: #{entry}"
|
1220
1575
|
end
|
1221
1576
|
|
1222
1577
|
# per-entry resource or log_name overrides the corresponding field
|
@@ -1233,7 +1588,12 @@ module BaseTest
|
|
1233
1588
|
assert_equal params[:resource][:type], resource['type']
|
1234
1589
|
check_labels resource['labels'], params[:resource][:labels]
|
1235
1590
|
check_labels labels, params[:labels]
|
1236
|
-
|
1591
|
+
if block_given?
|
1592
|
+
yield(entry, i)
|
1593
|
+
elsif payload_type == 'textPayload'
|
1594
|
+
# Check the payload for textPayload, otherwise it's up to the caller.
|
1595
|
+
verify_default_log_entry_text(entry['textPayload'], i, entry)
|
1596
|
+
end
|
1237
1597
|
i += 1
|
1238
1598
|
assert i <= n, "Number of entries #{i} exceeds expected number #{n}"
|
1239
1599
|
end
|
@@ -1251,7 +1611,8 @@ module BaseTest
|
|
1251
1611
|
n.times { |i| d.emit(log_entry_factory.call(log_entry(i))) }
|
1252
1612
|
d.run
|
1253
1613
|
end
|
1254
|
-
verify_log_entries(n, expected_params) do |entry|
|
1614
|
+
verify_log_entries(n, expected_params) do |entry, i|
|
1615
|
+
verify_default_log_entry_text(entry['textPayload'], i, entry)
|
1255
1616
|
assert_equal CONTAINER_SECONDS_EPOCH, entry['timestamp']['seconds'],
|
1256
1617
|
entry
|
1257
1618
|
assert_equal CONTAINER_NANOS, entry['timestamp']['nanos'], entry
|