fluent-plugin-google-cloud 0.7.4 → 0.7.5.pre.multiworkers

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 06aaf110596026347ea18bcd75c92554fd538e72f780efd7752e4624a08ae41c
4
- data.tar.gz: 8e6bcbbb5894193776d91121afb143a6de3da72000c544446ec9ae21c040109a
2
+ SHA1:
3
+ metadata.gz: be98011ce135e9570444d3c55967c316a96a858c
4
+ data.tar.gz: 88271c68f053f89f462ad8b5ed6b1fb2220e2bdc
5
5
  SHA512:
6
- metadata.gz: c19342019d92d4724a0d8f4b9dd8d0e0248b4e95b94394657d1c2be0b985d5a6b7c4787856164711112c51bbbe311b0495031412acbcae655519ed318bd3f2a5
7
- data.tar.gz: 8a18fbca8b05b67fa49f8dfa2b840a629ed55903a2079c9c27a39a31d78a25e1ddca8d7f347d9abae5f1cdb939603c67ff393a72db43cb0fb5a33d577b4cff12
6
+ metadata.gz: 279c39e5dcb334c48894dc970234fe780dfde6bb342f76715988730e72731accade84a6fafdcbc39ddd65087609ac11d274d693047818786034c3219ebcc22cb
7
+ data.tar.gz: 34e85bc20d7abf886508d1036a00b4ff1296dcea427da2b3870ca858a11e3217a57a397d4d72c0cfc06c74f015ccf5eb9a9dcd4fede4930c2625968b74fd31a4
@@ -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.7.4'
13
+ gem.version = '0.7.5.pre.multiworkers'
14
14
  gem.authors = ['Stackdriver Agents Team']
15
15
  gem.email = ['stackdriver-agents@google.com']
16
16
  gem.required_ruby_version = Gem::Requirement.new('>= 2.2')
@@ -95,6 +95,9 @@ module Fluent
95
95
  K8S_CONTAINER_CONSTANTS = {
96
96
  resource_type: 'k8s_container'
97
97
  }.freeze
98
+ K8S_POD_CONSTANTS = {
99
+ resource_type: 'k8s_pod'
100
+ }.freeze
98
101
  K8S_NODE_CONSTANTS = {
99
102
  resource_type: 'k8s_node'
100
103
  }.freeze
@@ -143,12 +146,13 @@ module Fluent
143
146
  # Default values for JSON payload keys to set the "httpRequest",
144
147
  # "operation", "sourceLocation", "trace" fields in the LogEntry.
145
148
  DEFAULT_HTTP_REQUEST_KEY = 'httpRequest'.freeze
149
+ DEFAULT_INSERT_ID_KEY = 'logging.googleapis.com/insertId'.freeze
150
+ DEFAULT_LABELS_KEY = 'logging.googleapis.com/labels'.freeze
146
151
  DEFAULT_OPERATION_KEY = 'logging.googleapis.com/operation'.freeze
147
152
  DEFAULT_SOURCE_LOCATION_KEY =
148
153
  'logging.googleapis.com/sourceLocation'.freeze
149
- DEFAULT_TRACE_KEY = 'logging.googleapis.com/trace'.freeze
150
154
  DEFAULT_SPAN_ID_KEY = 'logging.googleapis.com/spanId'.freeze
151
- DEFAULT_INSERT_ID_KEY = 'logging.googleapis.com/insertId'.freeze
155
+ DEFAULT_TRACE_KEY = 'logging.googleapis.com/trace'.freeze
152
156
 
153
157
  DEFAULT_METADATA_AGENT_URL =
154
158
  'http://local-metadata-agent.stackdriver.com:8000'.freeze
@@ -201,16 +205,6 @@ module Fluent
201
205
  # The non-grpc version class name.
202
206
  'Google::Apis::LoggingV2::HttpRequest'
203
207
  ],
204
- 'source_location' => [
205
- '@source_location_key',
206
- [
207
- %w(file file parse_string),
208
- %w(function function parse_string),
209
- %w(line line parse_int)
210
- ],
211
- 'Google::Logging::V2::LogEntrySourceLocation',
212
- 'Google::Apis::LoggingV2::LogEntrySourceLocation'
213
- ],
214
208
  'operation' => [
215
209
  '@operation_key',
216
210
  [
@@ -221,6 +215,16 @@ module Fluent
221
215
  ],
222
216
  'Google::Logging::V2::LogEntryOperation',
223
217
  'Google::Apis::LoggingV2::LogEntryOperation'
218
+ ],
219
+ 'source_location' => [
220
+ '@source_location_key',
221
+ [
222
+ %w(file file parse_string),
223
+ %w(function function parse_string),
224
+ %w(line line parse_int)
225
+ ],
226
+ 'Google::Logging::V2::LogEntrySourceLocation',
227
+ 'Google::Apis::LoggingV2::LogEntrySourceLocation'
224
228
  ]
225
229
  }.freeze
226
230
 
@@ -295,12 +299,13 @@ module Fluent
295
299
  # Map keys from a JSON payload to corresponding LogEntry fields.
296
300
  config_param :http_request_key, :string, :default =>
297
301
  DEFAULT_HTTP_REQUEST_KEY
302
+ config_param :insert_id_key, :string, :default => DEFAULT_INSERT_ID_KEY
303
+ config_param :labels_key, :string, :default => DEFAULT_LABELS_KEY
298
304
  config_param :operation_key, :string, :default => DEFAULT_OPERATION_KEY
299
305
  config_param :source_location_key, :string, :default =>
300
306
  DEFAULT_SOURCE_LOCATION_KEY
301
- config_param :trace_key, :string, :default => DEFAULT_TRACE_KEY
302
307
  config_param :span_id_key, :string, :default => DEFAULT_SPAN_ID_KEY
303
- config_param :insert_id_key, :string, :default => DEFAULT_INSERT_ID_KEY
308
+ config_param :trace_key, :string, :default => DEFAULT_TRACE_KEY
304
309
 
305
310
  # Whether to try to detect if the record is a text log entry with JSON
306
311
  # content that needs to be parsed.
@@ -617,6 +622,7 @@ module Fluent
617
622
  'severity',
618
623
  @http_request_key,
619
624
  @insert_id_key,
625
+ @labels_key,
620
626
  @operation_key,
621
627
  @source_location_key,
622
628
  @span_id_key,
@@ -650,6 +656,11 @@ module Fluent
650
656
  severity = compute_severity(
651
657
  entry_level_resource.type, record, entry_level_common_labels)
652
658
 
659
+ dynamic_labels_from_payload = parse_labels(record)
660
+
661
+ entry_level_common_labels = entry_level_common_labels.merge!(
662
+ dynamic_labels_from_payload) if dynamic_labels_from_payload
663
+
653
664
  entry = @construct_log_entry.call(entry_level_common_labels,
654
665
  entry_level_resource,
655
666
  severity,
@@ -1178,6 +1189,8 @@ module Fluent
1178
1189
 
1179
1190
  # GCE.
1180
1191
  when COMPUTE_CONSTANTS[:resource_type]
1192
+ raise "Cannot construct a #{type} resource without vm_id and zone" \
1193
+ unless @vm_id && @zone
1181
1194
  return {
1182
1195
  'instance_id' => @vm_id,
1183
1196
  'zone' => @zone
@@ -1185,6 +1198,8 @@ module Fluent
1185
1198
 
1186
1199
  # GKE container.
1187
1200
  when GKE_CONSTANTS[:resource_type]
1201
+ raise "Cannot construct a #{type} resource without vm_id and zone" \
1202
+ unless @vm_id && @zone
1188
1203
  return {
1189
1204
  'instance_id' => @vm_id,
1190
1205
  'zone' => @zone,
@@ -1205,6 +1220,8 @@ module Fluent
1205
1220
 
1206
1221
  # EC2.
1207
1222
  when EC2_CONSTANTS[:resource_type]
1223
+ raise "Cannot construct a #{type} resource without vm_id and zone" \
1224
+ unless @vm_id && @zone
1208
1225
  labels = {
1209
1226
  'instance_id' => @vm_id,
1210
1227
  'region' => @zone
@@ -1366,6 +1383,7 @@ module Fluent
1366
1383
  # TODO(qingling128): Temporary fallback for metadata agent restarts.
1367
1384
  # K8s resources.
1368
1385
  when K8S_CONTAINER_CONSTANTS[:resource_type],
1386
+ K8S_POD_CONSTANTS[:resource_type],
1369
1387
  K8S_NODE_CONSTANTS[:resource_type]
1370
1388
  common_labels.delete("#{COMPUTE_CONSTANTS[:service]}/resource_name")
1371
1389
 
@@ -1685,6 +1703,10 @@ module Fluent
1685
1703
  end
1686
1704
 
1687
1705
  def set_log_entry_fields(record, entry)
1706
+ # TODO(qingling128) On the next major after 0.7.4, make all logEntry
1707
+ # subfields behave the same way: if the field is not in the correct
1708
+ # format, log an error in the Fluentd log and remove this field from
1709
+ # payload. This is the preferred behavior per PM decision.
1688
1710
  LOG_ENTRY_FIELDS_MAP.each do |field_name, config|
1689
1711
  payload_key, subfields, grpc_class, non_grpc_class = config
1690
1712
  begin
@@ -1728,6 +1750,31 @@ module Fluent
1728
1750
  end
1729
1751
  end
1730
1752
 
1753
+ # Parse labels. Return nil if not set.
1754
+ def parse_labels(record)
1755
+ payload_labels = record.delete(@labels_key)
1756
+ return nil unless payload_labels
1757
+ unless payload_labels.is_a?(Hash)
1758
+ @log.error "Invalid value of '#{@labels_key}' in the payload: " \
1759
+ "#{payload_labels}. Labels need to be a JSON object."
1760
+ return nil
1761
+ end
1762
+
1763
+ non_string_keys = payload_labels.each_with_object([]) do |(k, v), a|
1764
+ a << k unless k.is_a?(String) && v.is_a?(String)
1765
+ end
1766
+ unless non_string_keys.empty?
1767
+ @log.error "Invalid value of '#{@labels_key}' in the payload: " \
1768
+ "#{payload_labels}. Labels need string values for all " \
1769
+ "keys; keys #{non_string_keys} don't."
1770
+ return nil
1771
+ end
1772
+ payload_labels
1773
+ rescue StandardError => err
1774
+ @log.error "Failed to extract '#{@labels_key}' from payload.", err
1775
+ return nil
1776
+ end
1777
+
1731
1778
  # Values permitted by the API for 'severity' (which is an enum).
1732
1779
  VALID_SEVERITIES = Set.new(
1733
1780
  %w(DEFAULT DEBUG INFO NOTICE WARNING ERROR CRITICAL ALERT EMERGENCY)
@@ -1875,6 +1922,10 @@ module Fluent
1875
1922
  .gsub('p.p', '.')
1876
1923
  end
1877
1924
 
1925
+ def multi_workers_ready?
1926
+ true
1927
+ end
1928
+
1878
1929
  def format(tag, time, record)
1879
1930
  Fluent::Engine.msgpack_factory.packer.write([tag, time, record]).to_s
1880
1931
  end
@@ -2260,6 +2311,10 @@ module Fluent
2260
2311
  \.(?<namespace_name>[0-9a-z-]+)
2261
2312
  \.(?<pod_name>[.0-9a-z-]+)
2262
2313
  \.(?<container_name>[0-9a-z-]+)$/x =~ local_resource_id ||
2314
+ /^
2315
+ (?<resource_type>k8s_pod)
2316
+ \.(?<namespace_name>[0-9a-z-]+)
2317
+ \.(?<pod_name>[.0-9a-z-]+)$/x =~ local_resource_id ||
2263
2318
  /^
2264
2319
  (?<resource_type>k8s_node)
2265
2320
  \.(?<node_name>[0-9a-z-]+)$/x =~ local_resource_id
@@ -2287,6 +2342,14 @@ module Fluent
2287
2342
  'location' => @k8s_cluster_location
2288
2343
  }
2289
2344
  fallback_resource = GKE_CONSTANTS[:resource_type]
2345
+ when K8S_POD_CONSTANTS[:resource_type]
2346
+ labels = {
2347
+ 'namespace_name' => namespace_name,
2348
+ 'pod_name' => pod_name,
2349
+ 'cluster_name' => @k8s_cluster_name,
2350
+ 'location' => @k8s_cluster_location
2351
+ }
2352
+ fallback_resource = GKE_CONSTANTS[:resource_type]
2290
2353
  when K8S_NODE_CONSTANTS[:resource_type]
2291
2354
  labels = {
2292
2355
  'node_name' => node_name,
@@ -626,7 +626,9 @@ module BaseTest
626
626
  end
627
627
  d.run
628
628
  end
629
- verify_log_entries(3, COMPUTE_PARAMS, 'jsonPayload') do |entry|
629
+ expected_params = COMPUTE_PARAMS.merge(
630
+ labels: COMPUTE_PARAMS[:labels].merge(LABELS_MESSAGE))
631
+ verify_log_entries(3, expected_params, 'jsonPayload') do |entry|
630
632
  fields = get_fields(entry['jsonPayload'])
631
633
  assert_equal 4, fields.size, entry
632
634
  assert_equal 'test log entry 0', get_string(fields['msg']), entry
@@ -1249,14 +1251,18 @@ module BaseTest
1249
1251
  verify_subfields_from_record(DEFAULT_HTTP_REQUEST_KEY)
1250
1252
  end
1251
1253
 
1252
- def test_log_entry_source_location_field_from_record
1253
- verify_subfields_from_record(DEFAULT_SOURCE_LOCATION_KEY)
1254
+ def test_log_entry_labels_field_from_record
1255
+ verify_subfields_from_record(DEFAULT_LABELS_KEY, false)
1254
1256
  end
1255
1257
 
1256
1258
  def test_log_entry_operation_field_from_record
1257
1259
  verify_subfields_from_record(DEFAULT_OPERATION_KEY)
1258
1260
  end
1259
1261
 
1262
+ def test_log_entry_source_location_field_from_record
1263
+ verify_subfields_from_record(DEFAULT_SOURCE_LOCATION_KEY)
1264
+ end
1265
+
1260
1266
  # Verify the subfields extraction of LogEntry fields when there are other
1261
1267
  # fields.
1262
1268
 
@@ -1264,26 +1270,48 @@ module BaseTest
1264
1270
  verify_subfields_partial_from_record(DEFAULT_HTTP_REQUEST_KEY)
1265
1271
  end
1266
1272
 
1267
- def test_log_entry_source_location_field_partial_from_record
1268
- verify_subfields_partial_from_record(DEFAULT_SOURCE_LOCATION_KEY)
1269
- end
1273
+ # We don't need a test like 'test_log_entry_labels_field_partial_from_record'
1274
+ # because labels are free range strings. Everything in the labels field should
1275
+ # be in the resulting logEntry->labels field. There is no need to check
1276
+ # partial transformation (aka, some 'labels' fields are extracted, while
1277
+ # others are left as it is).
1270
1278
 
1271
1279
  def test_log_entry_operation_field_partial_from_record
1272
1280
  verify_subfields_partial_from_record(DEFAULT_OPERATION_KEY)
1273
1281
  end
1274
1282
 
1283
+ def test_log_entry_source_location_field_partial_from_record
1284
+ verify_subfields_partial_from_record(DEFAULT_SOURCE_LOCATION_KEY)
1285
+ end
1286
+
1275
1287
  # Verify the subfields extraction of LogEntry fields when they are not hashes.
1276
1288
 
1277
1289
  def test_log_entry_http_request_field_when_not_hash
1278
- verify_subfields_when_not_hash(DEFAULT_HTTP_REQUEST_KEY)
1290
+ # TODO(qingling128) On the next major after 0.7.4, make all logEntry
1291
+ # subfields behave the same way: if the field is not in the correct format,
1292
+ # log an error in the Fluentd log and remove this field from payload. This
1293
+ # is the preferred behavior per PM decision.
1294
+ verify_subfields_untouched_when_not_hash(DEFAULT_HTTP_REQUEST_KEY)
1279
1295
  end
1280
1296
 
1281
- def test_log_entry_source_location_field_when_not_hash
1282
- verify_subfields_when_not_hash(DEFAULT_SOURCE_LOCATION_KEY)
1297
+ def test_log_entry_labels_field_when_not_hash
1298
+ verify_subfields_removed_when_not_hash(DEFAULT_LABELS_KEY)
1283
1299
  end
1284
1300
 
1285
1301
  def test_log_entry_operation_field_when_not_hash
1286
- verify_subfields_when_not_hash(DEFAULT_OPERATION_KEY)
1302
+ # TODO(qingling128) On the next major after 0.7.4, make all logEntry
1303
+ # subfields behave the same way: if the field is not in the correct format,
1304
+ # log an error in the Fluentd log and remove this field from payload. This
1305
+ # is the preferred behavior per PM decision.
1306
+ verify_subfields_untouched_when_not_hash(DEFAULT_OPERATION_KEY)
1307
+ end
1308
+
1309
+ def test_log_entry_source_location_field_when_not_hash
1310
+ # TODO(qingling128) On the next major after 0.7.4, make all logEntry
1311
+ # subfields behave the same way: if the field is not in the correct format,
1312
+ # log an error in the Fluentd log and remove this field from payload. This
1313
+ # is the preferred behavior per PM decision.
1314
+ verify_subfields_untouched_when_not_hash(DEFAULT_SOURCE_LOCATION_KEY)
1287
1315
  end
1288
1316
 
1289
1317
  # Verify the subfields extraction of LogEntry fields when they are nil.
@@ -1292,14 +1320,18 @@ module BaseTest
1292
1320
  verify_subfields_when_nil(DEFAULT_HTTP_REQUEST_KEY)
1293
1321
  end
1294
1322
 
1295
- def test_log_entry_source_location_field_when_nil
1296
- verify_subfields_when_nil(DEFAULT_SOURCE_LOCATION_KEY)
1323
+ def test_log_entry_labels_field_when_nil
1324
+ verify_subfields_when_nil(DEFAULT_LABELS_KEY)
1297
1325
  end
1298
1326
 
1299
1327
  def test_log_entry_operation_field_when_nil
1300
1328
  verify_subfields_when_nil(DEFAULT_OPERATION_KEY)
1301
1329
  end
1302
1330
 
1331
+ def test_log_entry_source_location_field_when_nil
1332
+ verify_subfields_when_nil(DEFAULT_SOURCE_LOCATION_KEY)
1333
+ end
1334
+
1303
1335
  def test_http_request_from_record_with_referer_nil_or_absent
1304
1336
  setup_gce_metadata_stubs
1305
1337
  [
@@ -1360,30 +1392,54 @@ module BaseTest
1360
1392
  # Verify the default and customization of LogEntry field extraction key.
1361
1393
 
1362
1394
  def test_log_entry_insert_id_field
1363
- verify_field_key('insertId', DEFAULT_INSERT_ID_KEY, 'custom_insert_id_key',
1364
- CONFIG_CUSTOM_INSERT_ID_KEY_SPECIFIED, INSERT_ID)
1395
+ verify_field_key('insertId',
1396
+ default_key: DEFAULT_INSERT_ID_KEY,
1397
+ custom_key: 'custom_insert_id_key',
1398
+ custom_key_config: CONFIG_CUSTOM_INSERT_ID_KEY_SPECIFIED,
1399
+ sample_value: INSERT_ID)
1400
+ end
1401
+
1402
+ def test_log_entry_labels_field
1403
+ verify_field_key('labels',
1404
+ default_key: DEFAULT_LABELS_KEY,
1405
+ custom_key: 'custom_labels_key',
1406
+ custom_key_config: CONFIG_CUSTOM_LABELS_KEY_SPECIFIED,
1407
+ sample_value: COMPUTE_PARAMS[:labels].merge(
1408
+ LABELS_MESSAGE),
1409
+ default_value: COMPUTE_PARAMS[:labels])
1365
1410
  end
1366
1411
 
1367
1412
  def test_log_entry_operation_field
1368
- verify_field_key('operation', DEFAULT_OPERATION_KEY, 'custom_operation_key',
1369
- CONFIG_CUSTOM_OPERATION_KEY_SPECIFIED, OPERATION_MESSAGE)
1413
+ verify_field_key('operation',
1414
+ default_key: DEFAULT_OPERATION_KEY,
1415
+ custom_key: 'custom_operation_key',
1416
+ custom_key_config: CONFIG_CUSTOM_OPERATION_KEY_SPECIFIED,
1417
+ sample_value: OPERATION_MESSAGE)
1370
1418
  end
1371
1419
 
1372
1420
  def test_log_entry_source_location_field
1373
- verify_field_key('sourceLocation', DEFAULT_SOURCE_LOCATION_KEY,
1374
- 'custom_source_location_key',
1375
- CONFIG_CUSTOM_SOURCE_LOCATION_KEY_SPECIFIED,
1376
- source_location_message)
1421
+ verify_field_key('sourceLocation',
1422
+ default_key: DEFAULT_SOURCE_LOCATION_KEY,
1423
+ custom_key: 'custom_source_location_key',
1424
+ custom_key_config: \
1425
+ CONFIG_CUSTOM_SOURCE_LOCATION_KEY_SPECIFIED,
1426
+ sample_value: source_location_message)
1377
1427
  end
1378
1428
 
1379
1429
  def test_log_entry_span_id_field
1380
- verify_field_key('spanId', DEFAULT_SPAN_ID_KEY, 'custom_span_id_key',
1381
- CONFIG_CUSTOM_SPAN_ID_KEY_SPECIFIED, SPAN_ID)
1430
+ verify_field_key('spanId',
1431
+ default_key: DEFAULT_SPAN_ID_KEY,
1432
+ custom_key: 'custom_span_id_key',
1433
+ custom_key_config: CONFIG_CUSTOM_SPAN_ID_KEY_SPECIFIED,
1434
+ sample_value: SPAN_ID)
1382
1435
  end
1383
1436
 
1384
1437
  def test_log_entry_trace_field
1385
- verify_field_key('trace', DEFAULT_TRACE_KEY, 'custom_trace_key',
1386
- CONFIG_CUSTOM_TRACE_KEY_SPECIFIED, TRACE)
1438
+ verify_field_key('trace',
1439
+ default_key: DEFAULT_TRACE_KEY,
1440
+ custom_key: 'custom_trace_key',
1441
+ custom_key_config: CONFIG_CUSTOM_TRACE_KEY_SPECIFIED,
1442
+ sample_value: TRACE)
1387
1443
  end
1388
1444
 
1389
1445
  # Verify the cascading JSON detection of LogEntry fields.
@@ -1395,6 +1451,16 @@ module BaseTest
1395
1451
  nested_level_value: INSERT_ID2)
1396
1452
  end
1397
1453
 
1454
+ def test_cascading_json_detection_with_log_entry_labels_field
1455
+ verify_cascading_json_detection_with_log_entry_fields(
1456
+ 'labels', DEFAULT_LABELS_KEY,
1457
+ root_level_value: LABELS_MESSAGE,
1458
+ nested_level_value: LABELS_MESSAGE2,
1459
+ expected_value_from_root: COMPUTE_PARAMS[:labels].merge(LABELS_MESSAGE),
1460
+ expected_value_from_nested: COMPUTE_PARAMS[:labels].merge(
1461
+ LABELS_MESSAGE2))
1462
+ end
1463
+
1398
1464
  def test_cascading_json_detection_with_log_entry_operation_field
1399
1465
  verify_cascading_json_detection_with_log_entry_fields(
1400
1466
  'operation', DEFAULT_OPERATION_KEY,
@@ -1424,6 +1490,82 @@ module BaseTest
1424
1490
  nested_level_value: TRACE2)
1425
1491
  end
1426
1492
 
1493
+ # Verify that labels present in multiple inputs respect the expected priority
1494
+ # order:
1495
+ # 1. Labels from the field "logging.googleapis.com/labels" in payload.
1496
+ # 2. Labels from the config "label_map".
1497
+ # 3. Labels from the config "labels".
1498
+ def test_labels_order
1499
+ [
1500
+ # Labels from the config "labels".
1501
+ {
1502
+ config: CONFIG_LABELS,
1503
+ emitted_log: {},
1504
+ expected_labels: LABELS_FROM_LABELS_CONFIG
1505
+ },
1506
+ # Labels from the config "label_map".
1507
+ {
1508
+ config: CONFIG_LABEL_MAP,
1509
+ emitted_log: PAYLOAD_FOR_LABEL_MAP,
1510
+ expected_labels: LABELS_FROM_LABEL_MAP_CONFIG
1511
+ },
1512
+ # Labels from the field "logging.googleapis.com/labels" in payload.
1513
+ {
1514
+ config: APPLICATION_DEFAULT_CONFIG,
1515
+ emitted_log: { DEFAULT_LABELS_KEY => LABELS_MESSAGE },
1516
+ expected_labels: LABELS_MESSAGE
1517
+ },
1518
+ # All three types of labels that do not conflict.
1519
+ {
1520
+ config: CONFIG_LABLES_AND_LABLE_MAP,
1521
+ emitted_log: PAYLOAD_FOR_LABEL_MAP.merge(
1522
+ DEFAULT_LABELS_KEY => LABELS_MESSAGE),
1523
+ expected_labels: LABELS_MESSAGE.merge(LABELS_FROM_LABELS_CONFIG).merge(
1524
+ LABELS_FROM_LABEL_MAP_CONFIG)
1525
+ },
1526
+ # labels from the config "labels" and "label_map" conflict.
1527
+ {
1528
+ config: CONFIG_LABLES_AND_LABLE_MAP_CONFLICTING,
1529
+ emitted_log: PAYLOAD_FOR_LABEL_MAP_CONFLICTING,
1530
+ expected_labels: LABELS_FROM_LABEL_MAP_CONFIG_CONFLICTING
1531
+ },
1532
+ # labels from the config "labels" and labels from the field
1533
+ # "logging.googleapis.com/labels" in payload conflict.
1534
+ {
1535
+ config: CONFIG_LABELS_CONFLICTING,
1536
+ emitted_log: { DEFAULT_LABELS_KEY => LABELS_FROM_PAYLOAD_CONFLICTING },
1537
+ expected_labels: LABELS_FROM_PAYLOAD_CONFLICTING
1538
+ },
1539
+ # labels from the config "label_map" and labels from the field
1540
+ # "logging.googleapis.com/labels" in payload conflict.
1541
+ {
1542
+ config: CONFIG_LABEL_MAP_CONFLICTING,
1543
+ emitted_log: PAYLOAD_FOR_LABEL_MAP_CONFLICTING.merge(
1544
+ DEFAULT_LABELS_KEY => LABELS_FROM_PAYLOAD_CONFLICTING),
1545
+ expected_labels: LABELS_FROM_PAYLOAD_CONFLICTING
1546
+ },
1547
+ # All three types of labels conflict.
1548
+ {
1549
+ config: CONFIG_LABLES_AND_LABLE_MAP_CONFLICTING,
1550
+ emitted_log: PAYLOAD_FOR_LABEL_MAP_CONFLICTING.merge(
1551
+ DEFAULT_LABELS_KEY => LABELS_FROM_PAYLOAD_CONFLICTING),
1552
+ expected_labels: LABELS_FROM_PAYLOAD_CONFLICTING
1553
+ }
1554
+ ].each do |test_params|
1555
+ new_stub_context do
1556
+ setup_gce_metadata_stubs
1557
+ setup_logging_stubs do
1558
+ d = create_driver(test_params[:config])
1559
+ d.emit({ 'message' => log_entry(0) }.merge(test_params[:emitted_log]))
1560
+ d.run
1561
+ end
1562
+ expected_params = COMPUTE_PARAMS.merge(
1563
+ labels: COMPUTE_PARAMS[:labels].merge(test_params[:expected_labels]))
1564
+ verify_log_entries(1, expected_params)
1565
+ end
1566
+ end
1567
+ end
1568
+
1427
1569
  # Metadata Agent related tests.
1428
1570
 
1429
1571
  # Test enable_metadata_agent not set or set to false.
@@ -1648,6 +1790,66 @@ module BaseTest
1648
1790
  end
1649
1791
  end
1650
1792
 
1793
+ # Test k8s_pod monitored resource including the fallback when Metadata Agent
1794
+ # restarts.
1795
+ def test_k8s_pod_monitored_resource_fallback
1796
+ [
1797
+ {
1798
+ config: APPLICATION_DEFAULT_CONFIG,
1799
+ setup_metadata_agent_stub: true,
1800
+ setup_k8s_stub: true,
1801
+ log_entry: k8s_pod_log_entry(log_entry(0)),
1802
+ expected_params: K8S_POD_PARAMS_FROM_LOCAL
1803
+ },
1804
+ {
1805
+ config: ENABLE_METADATA_AGENT_CONFIG,
1806
+ setup_metadata_agent_stub: false,
1807
+ setup_k8s_stub: true,
1808
+ log_entry: k8s_pod_log_entry(log_entry(0)),
1809
+ expected_params: K8S_POD_PARAMS_FROM_LOCAL
1810
+ },
1811
+ {
1812
+ config: CUSTOM_K8S_ENABLE_METADATA_AGENT_CONFIG,
1813
+ setup_metadata_agent_stub: false,
1814
+ setup_k8s_stub: false,
1815
+ log_entry: k8s_pod_log_entry(log_entry(0)),
1816
+ expected_params: K8S_POD_PARAMS_CUSTOM
1817
+ },
1818
+ {
1819
+ config: EMPTY_K8S_ENABLE_METADATA_AGENT_CONFIG,
1820
+ setup_metadata_agent_stub: true,
1821
+ setup_k8s_stub: true,
1822
+ log_entry: k8s_pod_log_entry(log_entry(0)),
1823
+ expected_params: K8S_POD_PARAMS
1824
+ },
1825
+ {
1826
+ config: ENABLE_METADATA_AGENT_CONFIG,
1827
+ setup_metadata_agent_stub: true,
1828
+ setup_k8s_stub: true,
1829
+ log_entry: k8s_pod_log_entry(log_entry(0)),
1830
+ expected_params: K8S_POD_PARAMS
1831
+ }
1832
+ ].each do |test_params|
1833
+ new_stub_context do
1834
+ setup_gce_metadata_stubs
1835
+ setup_metadata_agent_stubs(test_params[:setup_metadata_agent_stub])
1836
+ setup_k8s_metadata_stubs(test_params[:setup_k8s_stub])
1837
+ setup_logging_stubs do
1838
+ d = create_driver(test_params[:config])
1839
+ d.emit(test_params[:log_entry])
1840
+ d.run
1841
+ end
1842
+ verify_log_entries(1, test_params[:expected_params],
1843
+ 'jsonPayload') do |entry|
1844
+ fields = get_fields(entry['jsonPayload'])
1845
+ assert_equal 2, fields.size, entry
1846
+ assert_equal 'test log entry 0', get_string(fields['log']), entry
1847
+ assert_equal K8S_STREAM, get_string(fields['stream']), entry
1848
+ end
1849
+ end
1850
+ end
1851
+ end
1852
+
1651
1853
  # Test k8s_node monitored resource including the fallback when Metadata Agent
1652
1854
  # restarts.
1653
1855
  def test_k8s_node_monitored_resource_fallback
@@ -2023,6 +2225,18 @@ module BaseTest
2023
2225
  }
2024
2226
  end
2025
2227
 
2228
+ def k8s_pod_log_entry(log)
2229
+ {
2230
+ log: log,
2231
+ stream: K8S_STREAM,
2232
+ time: K8S_TIMESTAMP,
2233
+ LOCAL_RESOURCE_ID_KEY =>
2234
+ "#{K8S_POD_LOCAL_RESOURCE_ID_PREFIX}" \
2235
+ ".#{K8S_NAMESPACE_NAME}" \
2236
+ ".#{K8S_POD_NAME}"
2237
+ }
2238
+ end
2239
+
2026
2240
  def k8s_node_log_entry(log)
2027
2241
  {
2028
2242
  log: log,
@@ -2082,18 +2296,25 @@ module BaseTest
2082
2296
  "test log entry #{i}"
2083
2297
  end
2084
2298
 
2085
- def check_labels(labels, expected_labels)
2086
- return if labels.empty? && expected_labels.empty?
2087
- labels.each do |key, value|
2088
- assert value.is_a?(String), "Value #{value} for label #{key} " \
2089
- 'is not a string: ' + value.class.name
2090
- assert expected_labels.key?(key), "Unexpected label #{key} => #{value}"
2091
- assert_equal expected_labels[key], value, 'Value mismatch - expected ' \
2092
- "#{expected_labels[key]} in #{key} => #{value}"
2299
+ # If check_exact_labels is true, assert 'labels' and 'expected_labels' match
2300
+ # exactly. If check_exact_labels is false, assert 'labels' is a subset of
2301
+ # 'expected_labels'.
2302
+ def check_labels(expected_labels, labels, check_exact_labels = true)
2303
+ return if expected_labels.empty? && labels.empty?
2304
+ expected_labels.each do |expected_key, expected_value|
2305
+ assert labels.key?(expected_key), "Expected label #{expected_key} not" \
2306
+ " found. Got labels: #{labels}."
2307
+ actual_value = labels[expected_key]
2308
+ assert actual_value.is_a?(String), 'Value for label' \
2309
+ " #{expected_key} is not a string: #{actual_value}."
2310
+ assert_equal expected_value, actual_value, "Value for #{expected_key}" \
2311
+ " mismatch. Expected #{expected_value}. Got #{actual_value}"
2312
+ end
2313
+ if check_exact_labels
2314
+ assert_equal expected_labels.length, labels.length, 'Expected ' \
2315
+ "#{expected_labels.length} labels: #{expected_labels}, got " \
2316
+ "#{labels.length} labels: #{labels}"
2093
2317
  end
2094
- assert_equal expected_labels.length, labels.length, 'Expected ' \
2095
- "#{expected_labels.length} labels: #{expected_labels}, got " \
2096
- "#{labels.length} labels: #{labels}"
2097
2318
  end
2098
2319
 
2099
2320
  def verify_default_log_entry_text(text, i, entry)
@@ -2102,7 +2323,8 @@ module BaseTest
2102
2323
  end
2103
2324
 
2104
2325
  # The caller can optionally provide a block which is called for each entry.
2105
- def verify_json_log_entries(n, params, payload_type = 'textPayload')
2326
+ def verify_json_log_entries(n, params, payload_type = 'textPayload',
2327
+ check_exact_entry_labels = true)
2106
2328
  entry_count = 0
2107
2329
  @logs_sent.each do |request|
2108
2330
  request['entries'].each do |entry|
@@ -2127,8 +2349,10 @@ module BaseTest
2127
2349
  log_name
2128
2350
  end
2129
2351
  assert_equal params[:resource][:type], resource['type']
2130
- check_labels resource['labels'], params[:resource][:labels]
2131
- check_labels labels, params[:labels]
2352
+ check_labels params[:resource][:labels], resource['labels']
2353
+
2354
+ check_labels params[:labels], labels, check_exact_entry_labels
2355
+
2132
2356
  if block_given?
2133
2357
  yield(entry, entry_count)
2134
2358
  elsif payload_type == 'textPayload'
@@ -2170,14 +2394,16 @@ module BaseTest
2170
2394
  # the subfield in LogEntry object and the expected value of that field.
2171
2395
  DEFAULT_HTTP_REQUEST_KEY => [
2172
2396
  'httpRequest', http_request_message],
2173
- DEFAULT_SOURCE_LOCATION_KEY => [
2174
- 'sourceLocation', source_location_message],
2397
+ DEFAULT_LABELS_KEY => [
2398
+ 'labels', COMPUTE_PARAMS[:labels].merge(LABELS_MESSAGE)],
2175
2399
  DEFAULT_OPERATION_KEY => [
2176
- 'operation', OPERATION_MESSAGE]
2400
+ 'operation', OPERATION_MESSAGE],
2401
+ DEFAULT_SOURCE_LOCATION_KEY => [
2402
+ 'sourceLocation', source_location_message]
2177
2403
  }
2178
2404
  end
2179
2405
 
2180
- def verify_subfields_from_record(payload_key)
2406
+ def verify_subfields_from_record(payload_key, check_exact_entry_labels = true)
2181
2407
  destination_key, payload_value = log_entry_subfields_params[payload_key]
2182
2408
  @logs_sent = []
2183
2409
  setup_gce_metadata_stubs
@@ -2186,7 +2412,8 @@ module BaseTest
2186
2412
  d.emit(payload_key => payload_value)
2187
2413
  d.run
2188
2414
  end
2189
- verify_log_entries(1, COMPUTE_PARAMS, destination_key) do |entry|
2415
+ verify_log_entries(1, COMPUTE_PARAMS, destination_key,
2416
+ check_exact_entry_labels) do |entry|
2190
2417
  assert_equal payload_value, entry[destination_key], entry
2191
2418
  fields = get_fields(entry['jsonPayload'])
2192
2419
  assert_nil fields[payload_key], entry
@@ -2210,7 +2437,7 @@ module BaseTest
2210
2437
  end
2211
2438
  end
2212
2439
 
2213
- def verify_subfields_when_not_hash(payload_key)
2440
+ def verify_subfields_removed_when_not_hash(payload_key)
2214
2441
  destination_key = log_entry_subfields_params[payload_key][0]
2215
2442
  @logs_sent = []
2216
2443
  setup_gce_metadata_stubs
@@ -2220,6 +2447,25 @@ module BaseTest
2220
2447
  d.run
2221
2448
  end
2222
2449
  verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
2450
+ # The malformed field has been removed from the payload.
2451
+ assert_true get_fields(entry['jsonPayload']).empty?, entry
2452
+ # No additional labels.
2453
+ assert_equal COMPUTE_PARAMS[:labels].size,
2454
+ entry[destination_key].size, entry
2455
+ end
2456
+ end
2457
+
2458
+ def verify_subfields_untouched_when_not_hash(payload_key)
2459
+ destination_key = log_entry_subfields_params[payload_key][0]
2460
+ @logs_sent = []
2461
+ setup_gce_metadata_stubs
2462
+ setup_logging_stubs do
2463
+ d = create_driver
2464
+ d.emit(payload_key => 'a_string')
2465
+ d.run
2466
+ end
2467
+ verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
2468
+ # Verify that we leave the malformed field as it is.
2223
2469
  field = get_fields(entry['jsonPayload'])[payload_key]
2224
2470
  assert_equal 'a_string', get_string(field), entry
2225
2471
  assert_false entry.key?(destination_key), entry
@@ -2239,7 +2485,13 @@ module BaseTest
2239
2485
  verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
2240
2486
  fields = get_fields(entry['jsonPayload'])
2241
2487
  assert_false fields.key?(payload_key), entry
2242
- assert_false entry.key?(destination_key), entry
2488
+ if payload_key == DEFAULT_LABELS_KEY
2489
+ # No additional labels.
2490
+ assert_equal COMPUTE_PARAMS[:labels].size,
2491
+ entry[destination_key].size, entry
2492
+ else
2493
+ assert_false entry.key?(destination_key), entry
2494
+ end
2243
2495
  end
2244
2496
  end
2245
2497
 
@@ -2302,7 +2554,7 @@ module BaseTest
2302
2554
  d.emit(input_log_entry)
2303
2555
  d.run
2304
2556
  end
2305
- verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
2557
+ verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload', false) do |entry|
2306
2558
  assert_equal expected_value, entry[log_entry_field],
2307
2559
  "Index #{index} failed. #{expected_value} is expected" \
2308
2560
  " for #{log_entry_field} field."
@@ -2315,8 +2567,13 @@ module BaseTest
2315
2567
  end
2316
2568
  end
2317
2569
 
2318
- def verify_field_key(log_entry_field, default_key, custom_key,
2319
- custom_key_config, sample_value)
2570
+ def verify_field_key(log_entry_field, test_params)
2571
+ default_key = test_params[:default_key]
2572
+ custom_key = test_params[:custom_key]
2573
+ custom_key_config = test_params[:custom_key_config]
2574
+ sample_value = test_params[:sample_value]
2575
+ default_value = test_params.fetch(:default_value, nil)
2576
+
2320
2577
  setup_gce_metadata_stubs
2321
2578
  message = log_entry(0)
2322
2579
  [
@@ -2325,7 +2582,7 @@ module BaseTest
2325
2582
  driver_config: APPLICATION_DEFAULT_CONFIG,
2326
2583
  emitted_log: { 'msg' => message },
2327
2584
  expected_payload: { 'msg' => message },
2328
- expected_field_value: nil
2585
+ expected_field_value: default_value
2329
2586
  },
2330
2587
  {
2331
2588
  # By default, it sets log entry field via a default key.
@@ -2346,7 +2603,7 @@ module BaseTest
2346
2603
  driver_config: custom_key_config,
2347
2604
  emitted_log: { 'msg' => message, default_key => sample_value },
2348
2605
  expected_payload: { 'msg' => message, default_key => sample_value },
2349
- expected_field_value: nil
2606
+ expected_field_value: default_value
2350
2607
  }
2351
2608
  ].each do |input|
2352
2609
  setup_logging_stubs do
@@ -2355,7 +2612,7 @@ module BaseTest
2355
2612
  d.emit(input[:emitted_log])
2356
2613
  d.run
2357
2614
  end
2358
- verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
2615
+ verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload', false) do |entry|
2359
2616
  assert_equal input[:expected_field_value], entry[log_entry_field], input
2360
2617
  payload_fields = get_fields(entry['jsonPayload'])
2361
2618
  assert_equal input[:expected_payload].size, payload_fields.size, input
@@ -2413,7 +2670,8 @@ module BaseTest
2413
2670
 
2414
2671
  # Verify the number and the content of the log entries match the expectation.
2415
2672
  # The caller can optionally provide a block which is called for each entry.
2416
- def verify_log_entries(_n, _params, _payload_type = 'textPayload', &_block)
2673
+ def verify_log_entries(_n, _params, _payload_type = 'textPayload',
2674
+ _check_exact_entry_labels = true, &_block)
2417
2675
  _undefined
2418
2676
  end
2419
2677
 
@@ -156,6 +156,7 @@ module Constants
156
156
  K8S_SECONDS_EPOCH = 1_234_567_890
157
157
  K8S_NANOS = 987_654_321
158
158
  K8S_CONTAINER_LOCAL_RESOURCE_ID_PREFIX = 'k8s_container'.freeze
159
+ K8S_POD_LOCAL_RESOURCE_ID_PREFIX = 'k8s_pod'.freeze
159
160
  K8S_NODE_LOCAL_RESOURCE_ID_PREFIX = 'k8s_node'.freeze
160
161
  K8S_TAG =
161
162
  "var.log.containers.#{K8S_NAMESPACE_NAME}_#{K8S_POD_NAME}_" \
@@ -375,6 +376,10 @@ module Constants
375
376
  insert_id_key custom_insert_id_key
376
377
  ).freeze
377
378
 
379
+ CONFIG_CUSTOM_LABELS_KEY_SPECIFIED = %(
380
+ labels_key custom_labels_key
381
+ ).freeze
382
+
378
383
  CONFIG_CUSTOM_OPERATION_KEY_SPECIFIED = %(
379
384
  operation_key custom_operation_key
380
385
  ).freeze
@@ -391,6 +396,69 @@ module Constants
391
396
  trace_key custom_trace_key
392
397
  ).freeze
393
398
 
399
+ # For 'labels' config.
400
+ LABELS_FROM_LABELS_CONFIG = {
401
+ 'a_label_from_labels_config' => 'some_value',
402
+ 'another_label_from_labels_config' => 'some_value'
403
+ }.freeze
404
+ CONFIG_LABELS = %(
405
+ labels #{LABELS_FROM_LABELS_CONFIG.to_json}
406
+ ).freeze
407
+
408
+ # For 'label_map' config.
409
+ LABEL_MAP_HASH = {
410
+ 'target_field_from_payload' => 'a_label_from_label_map_config',
411
+ 'another_target_field_from_payload' => 'another_label_from_label_map_config'
412
+ }.freeze
413
+ PAYLOAD_FOR_LABEL_MAP = {
414
+ 'target_field_from_payload' => 'a_value',
415
+ 'another_target_field_from_payload' => 'b_value'
416
+ }.freeze
417
+ LABELS_FROM_LABEL_MAP_CONFIG = {
418
+ 'a_label_from_label_map_config' => 'a_value',
419
+ 'another_label_from_label_map_config' => 'b_value'
420
+ }.freeze
421
+ CONFIG_LABEL_MAP = %(
422
+ label_map #{LABEL_MAP_HASH.to_json}
423
+ ).freeze
424
+
425
+ CONFIG_LABLES_AND_LABLE_MAP = %(
426
+ #{CONFIG_LABELS}
427
+ #{CONFIG_LABEL_MAP}
428
+ ).freeze
429
+
430
+ # For conflicting labels.
431
+ CONFLICTING_LABEL_NAME = 'conflicting_label_key'.freeze
432
+ CONFLICTING_LABEL_VALUE1 = 'conflicting_value_1'.freeze
433
+ CONFLICTING_LABEL_VALUE2 = 'conflicting_value_2'.freeze
434
+ CONFLICTING_LABEL_VALUE3 = 'conflicting_value_3'.freeze
435
+ LABELS_FROM_PAYLOAD_CONFLICTING = {
436
+ CONFLICTING_LABEL_NAME => CONFLICTING_LABEL_VALUE1
437
+ }.freeze
438
+ LABELS_FROM_LABEL_MAP_CONFIG_CONFLICTING = {
439
+ CONFLICTING_LABEL_NAME => CONFLICTING_LABEL_VALUE2
440
+ }.freeze
441
+ LABELS_FROM_LABELS_CONFIG_CONFLICTING = {
442
+ CONFLICTING_LABEL_NAME => CONFLICTING_LABEL_VALUE3
443
+ }.freeze
444
+
445
+ LABEL_MAP_HASH_CONFLICTING = {
446
+ 'target_field_from_payload' => CONFLICTING_LABEL_NAME
447
+ }.freeze
448
+ PAYLOAD_FOR_LABEL_MAP_CONFLICTING = {
449
+ 'target_field_from_payload' => CONFLICTING_LABEL_VALUE2
450
+ }.freeze
451
+ CONFIG_LABEL_MAP_CONFLICTING = %(
452
+ label_map #{LABEL_MAP_HASH_CONFLICTING.to_json}
453
+ ).freeze
454
+ CONFIG_LABELS_CONFLICTING = %(
455
+ labels #{LABELS_FROM_LABELS_CONFIG_CONFLICTING.to_json}
456
+ ).freeze
457
+ CONFIG_LABLES_AND_LABLE_MAP_CONFLICTING = %(
458
+ #{CONFIG_LABELS_CONFLICTING}
459
+ #{CONFIG_LABEL_MAP_CONFLICTING}
460
+ ).freeze
461
+
394
462
  # Service configurations for various services.
395
463
 
396
464
  # GCE.
@@ -543,6 +611,36 @@ module Constants
543
611
  log_name: CONTAINER_TAG
544
612
  ).freeze
545
613
 
614
+ # K8s Pod.
615
+ K8S_POD_PARAMS = {
616
+ resource: {
617
+ type: K8S_POD_CONSTANTS[:resource_type],
618
+ labels: {
619
+ 'namespace_name' => K8S_NAMESPACE_NAME,
620
+ 'pod_name' => K8S_POD_NAME,
621
+ 'cluster_name' => K8S_CLUSTER_NAME,
622
+ 'location' => K8S_LOCATION
623
+ }
624
+ },
625
+ project_id: PROJECT_ID,
626
+ labels: {}
627
+ }.freeze
628
+ K8S_POD_PARAMS_FROM_LOCAL = K8S_POD_PARAMS.merge(
629
+ resource: K8S_POD_PARAMS[:resource].merge(
630
+ labels: K8S_POD_PARAMS[:resource][:labels].merge(
631
+ 'location' => K8S_LOCATION2
632
+ )
633
+ )
634
+ ).freeze
635
+ K8S_POD_PARAMS_CUSTOM = K8S_POD_PARAMS.merge(
636
+ resource: K8S_POD_PARAMS[:resource].merge(
637
+ labels: K8S_POD_PARAMS[:resource][:labels].merge(
638
+ 'cluster_name' => CUSTOM_K8S_CLUSTER_NAME,
639
+ 'location' => CUSTOM_K8S_LOCATION
640
+ )
641
+ )
642
+ ).freeze
643
+
546
644
  # K8s Node.
547
645
  K8S_NODE_PARAMS = {
548
646
  resource: {
@@ -781,6 +879,18 @@ module Constants
781
879
  'last' => false
782
880
  }.freeze
783
881
 
882
+ LABELS_MESSAGE = {
883
+ 'component' => 'front-end',
884
+ 'source' => 'user',
885
+ 'app' => 'request-router'
886
+ }.freeze
887
+
888
+ LABELS_MESSAGE2 = {
889
+ 'component' => 'front-end',
890
+ 'source' => 'system',
891
+ 'app' => 'request-router'
892
+ }.freeze
893
+
784
894
  CUSTOM_LABELS_MESSAGE = {
785
895
  'customKey' => 'value'
786
896
  }.freeze
@@ -858,6 +968,18 @@ module Constants
858
968
  'location' => K8S_LOCATION
859
969
  }
860
970
  }.to_json,
971
+ # K8s pod logs.
972
+ "#{K8S_POD_LOCAL_RESOURCE_ID_PREFIX}.#{K8S_NAMESPACE_NAME}" \
973
+ ".#{K8S_POD_NAME}" =>
974
+ {
975
+ 'type' => K8S_POD_CONSTANTS[:resource_type],
976
+ 'labels' => {
977
+ 'namespace_name' => K8S_NAMESPACE_NAME,
978
+ 'pod_name' => K8S_POD_NAME,
979
+ 'cluster_name' => K8S_CLUSTER_NAME,
980
+ 'location' => K8S_LOCATION
981
+ }
982
+ }.to_json,
861
983
  # K8s node logs.
862
984
  "#{K8S_NODE_LOCAL_RESOURCE_ID_PREFIX}.#{K8S_NODE_NAME}" =>
863
985
  {
@@ -980,6 +1102,7 @@ module Constants
980
1102
  'severity' => CONTAINER_SEVERITY,
981
1103
  DEFAULT_HTTP_REQUEST_KEY => HTTP_REQUEST_MESSAGE,
982
1104
  DEFAULT_INSERT_ID_KEY => INSERT_ID,
1105
+ DEFAULT_LABELS_KEY => LABELS_MESSAGE,
983
1106
  DEFAULT_OPERATION_KEY => OPERATION_MESSAGE,
984
1107
  DEFAULT_SOURCE_LOCATION_KEY => SOURCE_LOCATION_MESSAGE,
985
1108
  DEFAULT_SPAN_ID_KEY => SPAN_ID,
@@ -364,8 +364,10 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
364
364
 
365
365
  # Verify the number and the content of the log entries match the expectation.
366
366
  # The caller can optionally provide a block which is called for each entry.
367
- def verify_log_entries(n, params, payload_type = 'textPayload', &block)
368
- verify_json_log_entries(n, params, payload_type, &block)
367
+ def verify_log_entries(n, params, payload_type = 'textPayload',
368
+ check_exact_entry_labels = true, &block)
369
+ verify_json_log_entries(n, params, payload_type, check_exact_entry_labels,
370
+ &block)
369
371
  end
370
372
 
371
373
  # For an optional field with default values, Protobuf omits the field when it
@@ -413,7 +413,8 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
413
413
 
414
414
  # Verify the number and the content of the log entries match the expectation.
415
415
  # The caller can optionally provide a block which is called for each entry.
416
- def verify_log_entries(n, params, payload_type = 'textPayload', &block)
416
+ def verify_log_entries(n, params, payload_type = 'textPayload',
417
+ check_exact_entry_labels = true, &block)
417
418
  @requests_sent.each do |request|
418
419
  @logs_sent << {
419
420
  'entries' => request.entries.map { |entry| JSON.parse(entry.to_json) },
@@ -422,7 +423,8 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
422
423
  'logName' => request.log_name
423
424
  }
424
425
  end
425
- verify_json_log_entries(n, params, payload_type, &block)
426
+ verify_json_log_entries(n, params, payload_type, check_exact_entry_labels,
427
+ &block)
426
428
  end
427
429
 
428
430
  # Use the right single quotation mark as the sample non-utf8 character.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-google-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.4
4
+ version: 0.7.5.pre.multiworkers
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stackdriver Agents Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-02 00:00:00.000000000 Z
11
+ date: 2019-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -218,9 +218,7 @@ extensions: []
218
218
  extra_rdoc_files: []
219
219
  files:
220
220
  - CONTRIBUTING
221
- - CUSTOM_SPONGE_CONFIG
222
221
  - Gemfile
223
- - Gemfile.lock
224
222
  - LICENSE
225
223
  - README.rdoc
226
224
  - Rakefile
@@ -255,12 +253,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
255
253
  version: '2.2'
256
254
  required_rubygems_version: !ruby/object:Gem::Requirement
257
255
  requirements:
258
- - - ">="
256
+ - - ">"
259
257
  - !ruby/object:Gem::Version
260
- version: '0'
258
+ version: 1.3.1
261
259
  requirements: []
262
260
  rubyforge_project:
263
- rubygems_version: 2.7.8
261
+ rubygems_version: 2.6.14
264
262
  signing_key:
265
263
  specification_version: 4
266
264
  summary: fluentd plugins for the Stackdriver Logging API
data/CUSTOM_SPONGE_CONFIG DELETED
File without changes
data/Gemfile.lock DELETED
@@ -1,160 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- fluent-plugin-google-cloud (0.7.4)
5
- fluentd (= 1.2.5)
6
- google-api-client (= 0.23.9)
7
- google-cloud-logging (= 1.5.4)
8
- google-protobuf (= 3.6.1)
9
- googleapis-common-protos (= 1.3.7)
10
- googleauth (= 0.6.6)
11
- grpc (= 1.8.3)
12
- json (= 2.1.0)
13
-
14
- GEM
15
- remote: https://rubygems.org/
16
- specs:
17
- addressable (2.6.0)
18
- public_suffix (>= 2.0.2, < 4.0)
19
- ast (2.4.0)
20
- cool.io (1.5.3)
21
- crack (0.4.3)
22
- safe_yaml (~> 1.0.0)
23
- declarative (0.0.10)
24
- declarative-option (0.1.0)
25
- dig_rb (1.0.1)
26
- faraday (0.15.4)
27
- multipart-post (>= 1.2, < 3)
28
- fluentd (1.2.5)
29
- cool.io (>= 1.4.5, < 2.0.0)
30
- dig_rb (~> 1.0.0)
31
- http_parser.rb (>= 0.5.1, < 0.7.0)
32
- msgpack (>= 0.7.0, < 2.0.0)
33
- serverengine (>= 2.0.4, < 3.0.0)
34
- sigdump (~> 0.2.2)
35
- strptime (>= 0.2.2, < 1.0.0)
36
- tzinfo (~> 1.0)
37
- tzinfo-data (~> 1.0)
38
- yajl-ruby (~> 1.0)
39
- google-api-client (0.23.9)
40
- addressable (~> 2.5, >= 2.5.1)
41
- googleauth (>= 0.5, < 0.7.0)
42
- httpclient (>= 2.8.1, < 3.0)
43
- mime-types (~> 3.0)
44
- representable (~> 3.0)
45
- retriable (>= 2.0, < 4.0)
46
- signet (~> 0.9)
47
- google-cloud-core (1.3.0)
48
- google-cloud-env (~> 1.0)
49
- google-cloud-env (1.0.5)
50
- faraday (~> 0.11)
51
- google-cloud-logging (1.5.4)
52
- google-cloud-core (~> 1.2)
53
- google-gax (~> 1.3)
54
- googleapis-common-protos-types (>= 1.0.2)
55
- stackdriver-core (~> 1.3)
56
- google-gax (1.5.0)
57
- google-protobuf (~> 3.2)
58
- googleapis-common-protos (>= 1.3.5, < 2.0)
59
- googleauth (>= 0.6.2, < 0.10.0)
60
- grpc (>= 1.7.2, < 2.0)
61
- rly (~> 0.2.3)
62
- google-protobuf (3.6.1)
63
- googleapis-common-protos (1.3.7)
64
- google-protobuf (~> 3.0)
65
- googleapis-common-protos-types (~> 1.0)
66
- grpc (~> 1.0)
67
- googleapis-common-protos-types (1.0.2)
68
- google-protobuf (~> 3.0)
69
- googleauth (0.6.6)
70
- faraday (~> 0.12)
71
- jwt (>= 1.4, < 3.0)
72
- memoist (~> 0.12)
73
- multi_json (~> 1.11)
74
- os (>= 0.9, < 2.0)
75
- signet (~> 0.7)
76
- grpc (1.8.3)
77
- google-protobuf (~> 3.1)
78
- googleapis-common-protos-types (~> 1.0.0)
79
- googleauth (>= 0.5.1, < 0.7)
80
- hashdiff (0.3.8)
81
- http_parser.rb (0.6.0)
82
- httpclient (2.8.3)
83
- json (2.1.0)
84
- jwt (2.1.0)
85
- memoist (0.16.0)
86
- metaclass (0.0.4)
87
- mime-types (3.2.2)
88
- mime-types-data (~> 3.2015)
89
- mime-types-data (3.2018.0812)
90
- mocha (1.8.0)
91
- metaclass (~> 0.0.1)
92
- msgpack (1.2.6)
93
- multi_json (1.13.1)
94
- multipart-post (2.0.0)
95
- os (1.0.0)
96
- parser (2.6.0.0)
97
- ast (~> 2.4.0)
98
- power_assert (1.1.3)
99
- powerpack (0.1.2)
100
- prometheus-client (0.7.1)
101
- quantile (~> 0.2.0)
102
- public_suffix (3.0.3)
103
- quantile (0.2.1)
104
- rainbow (2.2.2)
105
- rake
106
- rake (10.5.0)
107
- representable (3.0.4)
108
- declarative (< 0.1.0)
109
- declarative-option (< 0.2.0)
110
- uber (< 0.2.0)
111
- retriable (3.1.2)
112
- rly (0.2.3)
113
- rubocop (0.39.0)
114
- parser (>= 2.3.0.7, < 3.0)
115
- powerpack (~> 0.1)
116
- rainbow (>= 1.99.1, < 3.0)
117
- ruby-progressbar (~> 1.7)
118
- unicode-display_width (~> 1.0, >= 1.0.1)
119
- ruby-progressbar (1.10.0)
120
- safe_yaml (1.0.4)
121
- serverengine (2.1.0)
122
- sigdump (~> 0.2.2)
123
- sigdump (0.2.4)
124
- signet (0.11.0)
125
- addressable (~> 2.3)
126
- faraday (~> 0.9)
127
- jwt (>= 1.5, < 3.0)
128
- multi_json (~> 1.10)
129
- stackdriver-core (1.3.3)
130
- google-cloud-core (~> 1.2)
131
- strptime (0.2.3)
132
- test-unit (3.3.0)
133
- power_assert
134
- thread_safe (0.3.6)
135
- tzinfo (1.2.5)
136
- thread_safe (~> 0.1)
137
- tzinfo-data (1.2018.9)
138
- tzinfo (>= 1.0.0)
139
- uber (0.1.0)
140
- unicode-display_width (1.4.1)
141
- webmock (2.3.2)
142
- addressable (>= 2.3.6)
143
- crack (>= 0.3.2)
144
- hashdiff
145
- yajl-ruby (1.4.1)
146
-
147
- PLATFORMS
148
- ruby
149
-
150
- DEPENDENCIES
151
- fluent-plugin-google-cloud!
152
- mocha (~> 1.1)
153
- prometheus-client (~> 0.7.1)
154
- rake (~> 10.3)
155
- rubocop (~> 0.39.0)
156
- test-unit (~> 3.0)
157
- webmock (~> 2.3.1)
158
-
159
- BUNDLED WITH
160
- 1.16.6