fluent-plugin-google-cloud 0.4.9 → 0.4.10

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: 2e57b5b102aadda45f4cbcab3f47d4a01ee863cd
4
- data.tar.gz: 16f62d33c58b8f6fef5385f7f8f0e4958b57de8d
3
+ metadata.gz: 8625be40328ad3c14dd4596985a1017092c2884a
4
+ data.tar.gz: d39dc933fdc5c0db8830c83ed94bd19f1db147da
5
5
  SHA512:
6
- metadata.gz: d1b6ccd7dc730e086f26f09820a8ba32f32872fb746a9e514bef5ae0b03971548ddcab6663470ee89c9700add1b8d663eb59a6838abc67445d4a2e8a2dbd159e
7
- data.tar.gz: a5dde71268839c39338e6257c29c3a77cebeea51c6b69c6ee0b56bb26fdeb4b8eb363197c508c36e34be4c237aef0baf6a908ec5358ac47ba35d7ea6e9aa3aaa
6
+ metadata.gz: d60286af889814e55fa15012b8fcdd5d1114ea2e14c420fdce8d7942d33479378e26cf2074cb02b2ab08a1943052a1f4ce3fa5de75a4526eeb0974c17c3e4da3
7
+ data.tar.gz: 67d62b7f2292cdc4d1a98aa5a7591d7d838ce923764c5055c5da3a92c00edbb84558b1e73535e758f7c335b29074c743c48a6439de42db1cff29d9cdab63788c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-google-cloud (0.4.8)
4
+ fluent-plugin-google-cloud (0.4.10)
5
5
  fluentd (>= 0.10)
6
6
  google-api-client (~> 0.8.6)
7
7
  googleauth (~> 0.4)
@@ -24,13 +24,13 @@ GEM
24
24
  addressable (>= 2.3.1)
25
25
  extlib (>= 0.9.15)
26
26
  multi_json (>= 1.0.0)
27
- cool.io (1.4.0)
27
+ cool.io (1.4.1)
28
28
  crack (0.4.2)
29
29
  safe_yaml (~> 1.0.0)
30
30
  extlib (0.9.16)
31
- faraday (0.9.1)
31
+ faraday (0.9.2)
32
32
  multipart-post (>= 1.2, < 3)
33
- fluentd (0.12.15)
33
+ fluentd (0.12.16)
34
34
  cool.io (>= 1.2.2, < 2.0.0)
35
35
  http_parser.rb (>= 0.5.1, < 0.7.0)
36
36
  json (>= 1.4.3)
@@ -70,7 +70,7 @@ GEM
70
70
  multi_json (~> 1.10)
71
71
  memoist (0.12.0)
72
72
  metaclass (0.0.4)
73
- minitest (5.8.0)
73
+ minitest (5.8.1)
74
74
  mocha (1.1.0)
75
75
  metaclass (~> 0.0.1)
76
76
  msgpack (0.5.12)
@@ -104,7 +104,7 @@ GEM
104
104
  thread_safe (0.3.5)
105
105
  tzinfo (1.2.2)
106
106
  thread_safe (~> 0.1)
107
- tzinfo-data (1.2015.6)
107
+ tzinfo-data (1.2015.7)
108
108
  tzinfo (>= 1.0.0)
109
109
  webmock (1.21.0)
110
110
  addressable (>= 2.3.6)
@@ -121,3 +121,6 @@ DEPENDENCIES
121
121
  rubocop (~> 0.33.0)
122
122
  test-unit (~> 3.0.2)
123
123
  webmock (>= 1.17.0)
124
+
125
+ BUNDLED WITH
126
+ 1.10.6
@@ -10,7 +10,7 @@ eos
10
10
  gem.homepage = \
11
11
  'https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud'
12
12
  gem.license = 'Apache 2.0'
13
- gem.version = '0.4.9'
13
+ gem.version = '0.4.10'
14
14
  gem.authors = ['Todd Derr', 'Alex Robinson']
15
15
  gem.email = ['salty@google.com']
16
16
 
@@ -156,7 +156,7 @@ module Fluent
156
156
  end
157
157
 
158
158
  @cloudfunctions_tag_regexp =
159
- /\.(?<function_name>.+)-[^-]+_default_worker$/
159
+ /\.(?<function_name>[^.]+)(?:\.\d+)?-[^-]+_default_worker$/
160
160
  @cloudfunctions_log_regexp = /^
161
161
  (?:\[(?<severity>.)\])?
162
162
  \[(?<timestamp>.{24})\]
@@ -326,12 +326,54 @@ module Fluent
326
326
  @service_name = CONTAINER_SERVICE
327
327
  end
328
328
  end
329
+ is_container_json = nil
329
330
  arr.each do |time, record|
330
331
  next unless record.is_a?(Hash)
332
+
333
+ entry = {
334
+ 'metadata' => {
335
+ 'serviceName' => @service_name,
336
+ 'projectId' => @project_id,
337
+ 'zone' => @zone,
338
+ 'labels' => {}
339
+ }
340
+ }
341
+
331
342
  if @service_name == CLOUDFUNCTIONS_SERVICE && record.key?('log')
332
343
  @cloudfunctions_log_match =
333
344
  @cloudfunctions_log_regexp.match(record['log'])
334
345
  end
346
+ if @service_name == CONTAINER_SERVICE
347
+ # Move the stdout/stderr annotation from the record into a label
348
+ field_to_label(record, 'stream', entry['metadata']['labels'],
349
+ "#{CONTAINER_SERVICE}/stream")
350
+ # If the record has been annotated by the kubernetes_metadata_filter
351
+ # plugin, then use that metadata. Otherwise, rely on commonLabels
352
+ # populated at the grouped_entries level from the group's tag.
353
+ if record.key?('kubernetes')
354
+ handle_container_metadata(record, entry)
355
+ end
356
+ # If the log from the user container is json, we want to export it
357
+ # as a structured log. Now that we've pulled out all the
358
+ # container-specific metadata from the record, we can replace the
359
+ # record with the json that the user logged.
360
+ # To save CPU in the common case of unstructured logs, only check if
361
+ # the contents are parsable as json for the first entry of each
362
+ # batch.
363
+ if is_container_json.nil? && record.key?('log')
364
+ record_json = parse_json_or_nil(record['log'])
365
+ if record_json.nil?
366
+ is_container_json = false
367
+ else
368
+ record = record_json
369
+ is_container_json = true
370
+ end
371
+ elsif is_container_json && record.key?('log')
372
+ record_json = parse_json_or_nil(record['log'])
373
+ record = record_json unless record_json.nil?
374
+ end
375
+ end
376
+
335
377
  if record.key?('timestamp') &&
336
378
  record['timestamp'].is_a?(Hash) &&
337
379
  record['timestamp'].key?('seconds') &&
@@ -367,33 +409,13 @@ module Fluent
367
409
  ts_secs = timestamp.tv_sec
368
410
  ts_nanos = timestamp.tv_nsec
369
411
  end
370
- entry = {
371
- 'metadata' => {
372
- 'serviceName' => @service_name,
373
- 'projectId' => @project_id,
374
- 'zone' => @zone,
375
- 'timestamp' => {
376
- 'seconds' => ts_secs,
377
- 'nanos' => ts_nanos
378
- },
379
- 'labels' => {}
380
- }
412
+ entry['metadata']['timestamp'] = {
413
+ 'seconds' => ts_secs,
414
+ 'nanos' => ts_nanos
381
415
  }
382
416
 
383
417
  set_severity(record, entry)
384
418
 
385
- if @service_name == CONTAINER_SERVICE
386
- # Move the stdout/stderr annotation from the record into a label
387
- field_to_label(record, 'stream', entry['metadata']['labels'],
388
- "#{CONTAINER_SERVICE}/stream")
389
- # If the record has been annotated by the kubernetes_metadata_filter
390
- # plugin, then use that metadata. Otherwise, rely on commonLabels
391
- # populated at the grouped_entries level from the group's tag.
392
- if record.key?('kubernetes')
393
- handle_container_metadata(record, entry)
394
- end
395
- end
396
-
397
419
  # If a field is present in the label_map, send its value as a label
398
420
  # (mapping the field name to label name as specified in the config)
399
421
  # and do not send that field as part of the payload.
@@ -410,7 +432,7 @@ module Fluent
410
432
  @cloudfunctions_log_match['execution_id']
411
433
  end
412
434
 
413
- set_payload(record, entry)
435
+ set_payload(record, entry, is_container_json)
414
436
 
415
437
  # Remove the labels metadata if we didn't populate it with anything.
416
438
  if entry['metadata']['labels'].empty?
@@ -478,6 +500,17 @@ module Fluent
478
500
  error_class: error.class.to_s, error: error.to_s
479
501
  end
480
502
 
503
+ def parse_json_or_nil(input)
504
+ # Only here to please rubocop...
505
+ return nil if input.nil?
506
+
507
+ begin
508
+ return JSON.parse(input)
509
+ rescue JSON::ParserError
510
+ return nil
511
+ end
512
+ end
513
+
481
514
  # "enum" of Platform values
482
515
  module Platform
483
516
  OTHER = 0 # Other/unkown platform
@@ -656,13 +689,18 @@ module Fluent
656
689
  record.delete(field)
657
690
  end
658
691
 
659
- def set_payload(record, entry)
660
- # Use textPayload if this is the Cloud Functions service and 'log' key is
661
- # available, or if the only remainaing key is 'message'.
692
+ def set_payload(record, entry, is_container_json)
693
+ # Use textPayload if
694
+ # 1. This is a Cloud Functions log that matched the expected regexp
695
+ # 2. This is a Cloud Functions log and the 'log' key is available
696
+ # 3. This is an unstructured Container log and the 'log' key is available
697
+ # 4. The only remaining key is 'message'
662
698
  if @service_name == CLOUDFUNCTIONS_SERVICE && @cloudfunctions_log_match
663
699
  entry['textPayload'] = @cloudfunctions_log_match['text']
664
- elsif (@service_name == CLOUDFUNCTIONS_SERVICE ||
665
- @service_name == CONTAINER_SERVICE) && record.key?('log')
700
+ elsif @service_name == CLOUDFUNCTIONS_SERVICE && record.key?('log')
701
+ entry['textPayload'] = record['log']
702
+ elsif @service_name == CONTAINER_SERVICE && record.key?('log') &&
703
+ !is_container_json
666
704
  entry['textPayload'] = record['log']
667
705
  elsif record.size == 1 && record.key?('message')
668
706
  entry['textPayload'] = record['message']
@@ -691,7 +729,7 @@ module Fluent
691
729
  def init_api_client
692
730
  @client = Google::APIClient.new(
693
731
  application_name: 'Fluentd Google Cloud Logging plugin',
694
- application_version: '0.4.9',
732
+ application_version: '0.4.10',
695
733
  retries: 1)
696
734
 
697
735
  if @auth_method == 'private_key'
@@ -75,7 +75,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
75
75
  CLOUDFUNCTIONS_EXECUTION_ID = '123-0'
76
76
  CLOUDFUNCTIONS_CLUSTER_NAME = 'cluster-1'
77
77
  CLOUDFUNCTIONS_NAMESPACE_NAME = 'default'
78
- CLOUDFUNCTIONS_POD_NAME = "#{CLOUDFUNCTIONS_FUNCTION_NAME}-c0l82"
78
+ CLOUDFUNCTIONS_POD_NAME = "#{CLOUDFUNCTIONS_FUNCTION_NAME}.987-c0l82"
79
79
  CLOUDFUNCTIONS_CONTAINER_NAME = 'worker'
80
80
 
81
81
  # Parameters used for authentication
@@ -854,7 +854,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
854
854
  setup_container_metadata_stubs
855
855
  setup_logging_stubs
856
856
  d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
857
- d.emit(container_log_entry_with_metadata(0))
857
+ d.emit(container_log_entry_with_metadata(log_entry(0)))
858
858
  d.run
859
859
  verify_log_entries(1, CONTAINER_FROM_METADATA_PARAMS)
860
860
  end
@@ -869,7 +869,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
869
869
  # do it manually here.
870
870
  d.instance_variable_get('@entries').clear
871
871
  @logs_sent = []
872
- n.times { |i| d.emit(container_log_entry_with_metadata(i)) }
872
+ n.times { |i| d.emit(container_log_entry_with_metadata(log_entry(i))) }
873
873
  d.run
874
874
  verify_log_entries(n, CONTAINER_FROM_METADATA_PARAMS)
875
875
  end
@@ -880,7 +880,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
880
880
  setup_container_metadata_stubs
881
881
  setup_logging_stubs
882
882
  d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
883
- d.emit(container_log_entry(0))
883
+ d.emit(container_log_entry(log_entry(0)))
884
884
  d.run
885
885
  verify_log_entries(1, CONTAINER_FROM_TAG_PARAMS)
886
886
  end
@@ -895,12 +895,46 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
895
895
  # do it manually here.
896
896
  d.instance_variable_get('@entries').clear
897
897
  @logs_sent = []
898
- n.times { |i| d.emit(container_log_entry(i)) }
898
+ n.times { |i| d.emit(container_log_entry(log_entry(i))) }
899
899
  d.run
900
900
  verify_log_entries(n, CONTAINER_FROM_TAG_PARAMS)
901
901
  end
902
902
  end
903
903
 
904
+ def test_struct_container_log_metadata_from_plugin
905
+ setup_gce_metadata_stubs
906
+ setup_container_metadata_stubs
907
+ setup_logging_stubs
908
+ d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
909
+ d.emit(container_log_entry_with_metadata('{"msg": "test log entry 0", ' \
910
+ '"tag2": "test", "data": 5000}'))
911
+ d.run
912
+ verify_log_entries(1, CONTAINER_FROM_METADATA_PARAMS,
913
+ 'structPayload') do |entry|
914
+ assert_equal 3, entry['structPayload'].size, entry
915
+ assert_equal 'test log entry 0', entry['structPayload']['msg'], entry
916
+ assert_equal 'test', entry['structPayload']['tag2'], entry
917
+ assert_equal 5000, entry['structPayload']['data'], entry
918
+ end
919
+ end
920
+
921
+ def test_struct_container_log_metadata_from_tag
922
+ setup_gce_metadata_stubs
923
+ setup_container_metadata_stubs
924
+ setup_logging_stubs
925
+ d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
926
+ d.emit(container_log_entry('{"msg": "test log entry 0", ' \
927
+ '"tag2": "test", "data": 5000}'))
928
+ d.run
929
+ verify_log_entries(1, CONTAINER_FROM_TAG_PARAMS,
930
+ 'structPayload') do |entry|
931
+ assert_equal 3, entry['structPayload'].size, entry
932
+ assert_equal 'test log entry 0', entry['structPayload']['msg'], entry
933
+ assert_equal 'test', entry['structPayload']['tag2'], entry
934
+ assert_equal 5000, entry['structPayload']['data'], entry
935
+ end
936
+ end
937
+
904
938
  def test_one_cloudfunctions_log
905
939
  setup_gce_metadata_stubs
906
940
  setup_cloudfunctions_metadata_stubs
@@ -1193,9 +1227,9 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
1193
1227
  stub_metadata_request('instance/attributes/gcf_region', 'us-central1')
1194
1228
  end
1195
1229
 
1196
- def container_log_entry_with_metadata(i)
1230
+ def container_log_entry_with_metadata(log)
1197
1231
  {
1198
- log: log_entry(i),
1232
+ log: log,
1199
1233
  stream: 'stdout',
1200
1234
  kubernetes: {
1201
1235
  namespace_id: CONTAINER_NAMESPACE_ID,
@@ -1207,9 +1241,9 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
1207
1241
  }
1208
1242
  end
1209
1243
 
1210
- def container_log_entry(i)
1244
+ def container_log_entry(log)
1211
1245
  {
1212
- log: log_entry(i),
1246
+ log: log,
1213
1247
  stream: 'stdout'
1214
1248
  }
1215
1249
  end
@@ -1253,7 +1287,8 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
1253
1287
  @logs_sent.each do |batch|
1254
1288
  batch['entries'].each do |entry|
1255
1289
  unless payload_type.empty?
1256
- assert entry.key?(payload_type)
1290
+ assert entry.key?(payload_type), 'Entry did not contain expected ' \
1291
+ "#{payload_type} key: " + entry.to_s
1257
1292
  # Check the payload for textPayload, otherwise it's up to the caller.
1258
1293
  if (payload_type == 'textPayload')
1259
1294
  assert_equal "test log entry #{i}", entry['textPayload'], batch
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-google-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.9
4
+ version: 0.4.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Derr
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-10-14 00:00:00.000000000 Z
12
+ date: 2015-10-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fluentd