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

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
- 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