fluent-plugin-google-cloud 0.5.3.grpc.alpha.4 → 0.5.3.grpc.alpha.5
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 +4 -4
- data/fluent-plugin-google-cloud.gemspec +1 -1
- data/lib/fluent/plugin/out_google_cloud.rb +26 -353
- data/test/plugin/base_test.rb +36 -31
- data/test/plugin/test_out_google_cloud.rb +33 -31
- data/test/plugin/test_out_google_cloud_grpc.rb +38 -31
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af37e8c845023885ae3cec2dcef35368f30e7ee3
|
4
|
+
data.tar.gz: 57cd2c566bb2c89ee063dbb12fbd02a75e8744c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8ca9cfcb3c564822cfd06870010e21358352612a401bdfda9c0d49f4715f9a0831e3daab338a69d9b584a2b568255aa2bae35e512771cfb837de74b64712be0
|
7
|
+
data.tar.gz: 43fa64e97398e3526a6153db587806b9a56291c330b6b066f5a7a106abf769c040cd4bb6a849a4d6bf7b8ba65427dc1a3b5cd5ff3a3ed156ee01e56f790005cf
|
@@ -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.5.3.grpc.alpha.
|
13
|
+
gem.version = '0.5.3.grpc.alpha.5'
|
14
14
|
gem.authors = ['Todd Derr', 'Alex Robinson']
|
15
15
|
gem.email = ['salty@google.com']
|
16
16
|
gem.required_ruby_version = Gem::Requirement.new('>= 2.0')
|
@@ -39,7 +39,7 @@ module Fluent
|
|
39
39
|
Fluent::Plugin.register_output('google_cloud', self)
|
40
40
|
|
41
41
|
PLUGIN_NAME = 'Fluentd Google Cloud Logging plugin'
|
42
|
-
PLUGIN_VERSION = '0.5.3.grpc.alpha.
|
42
|
+
PLUGIN_VERSION = '0.5.3.grpc.alpha.5'
|
43
43
|
|
44
44
|
# Constants for service names.
|
45
45
|
APPENGINE_SERVICE = 'appengine.googleapis.com'
|
@@ -599,338 +599,6 @@ module Fluent
|
|
599
599
|
end
|
600
600
|
end
|
601
601
|
|
602
|
-
# def old_write(chunk)
|
603
|
-
# # Group the entries since we have to make one call per tag.
|
604
|
-
# grouped_entries = {}
|
605
|
-
# chunk.msgpack_each do |tag, *arr|
|
606
|
-
# grouped_entries[tag] = [] unless grouped_entries.key?(tag)
|
607
|
-
# grouped_entries[tag].push(arr)
|
608
|
-
# end
|
609
|
-
#
|
610
|
-
# grouped_entries.each do |tag, arr|
|
611
|
-
# entries = []
|
612
|
-
# labels = @common_labels.clone
|
613
|
-
#
|
614
|
-
# if @running_cloudfunctions
|
615
|
-
# # If the current group of entries is coming from a Cloud Functions
|
616
|
-
# # function, the function name can be extracted from the tag.
|
617
|
-
# match_data = @cloudfunctions_tag_regexp.match(tag)
|
618
|
-
# if match_data
|
619
|
-
# # Service name is set to Cloud Functions only for logs actually
|
620
|
-
# # coming from a function.
|
621
|
-
# @service_name = CLOUDFUNCTIONS_SERVICE
|
622
|
-
# labels["#{CLOUDFUNCTIONS_SERVICE}/region"] = @gcf_region
|
623
|
-
# labels["#{CLOUDFUNCTIONS_SERVICE}/function_name"] =
|
624
|
-
# decode_cloudfunctions_function_name(
|
625
|
-
# match_data['encoded_function_name'])
|
626
|
-
# else
|
627
|
-
# # Other logs are considered as coming from the Container Engine
|
628
|
-
# # service.
|
629
|
-
# @service_name = CONTAINER_SERVICE
|
630
|
-
# end
|
631
|
-
# end
|
632
|
-
# if @service_name == CONTAINER_SERVICE && \
|
633
|
-
# @compiled_kubernetes_tag_regexp
|
634
|
-
# # Container logs in Kubernetes are tagged based on where they came
|
635
|
-
# # from, so we can extract useful metadata from the tag.
|
636
|
-
# # Do this here to avoid having to repeat it for each record.
|
637
|
-
# match_data = @compiled_kubernetes_tag_regexp.match(tag)
|
638
|
-
# if match_data
|
639
|
-
# %w(namespace_name pod_name container_name).each do |field|
|
640
|
-
# labels["#{CONTAINER_SERVICE}/#{field}"] = match_data[field]
|
641
|
-
# end
|
642
|
-
# end
|
643
|
-
# end
|
644
|
-
#
|
645
|
-
# if @use_grpc
|
646
|
-
# arr.each do |time, record|
|
647
|
-
# next unless record.is_a?(Hash)
|
648
|
-
#
|
649
|
-
# entry = Google::Logging::V1::LogEntry.new(
|
650
|
-
# metadata: Google::Logging::V1::LogEntryMetadata.new(
|
651
|
-
# service_name: @service_name.encode('utf-8'),
|
652
|
-
# project_id: @project_id.encode('utf-8'),
|
653
|
-
# zone: @zone.encode('utf-8'),
|
654
|
-
# labels: {}
|
655
|
-
# ))
|
656
|
-
#
|
657
|
-
# if @service_name == CLOUDFUNCTIONS_SERVICE && record.key?('log')
|
658
|
-
# @cloudfunctions_log_match =
|
659
|
-
# @cloudfunctions_log_regexp.match(record['log'])
|
660
|
-
# end
|
661
|
-
# if @service_name == CONTAINER_SERVICE
|
662
|
-
# # Move the stdout/stderr annotation from the record into a
|
663
|
-
# # label.
|
664
|
-
# field_to_label(record, 'stream', entry.metadata.labels,
|
665
|
-
# "#{CONTAINER_SERVICE}/stream")
|
666
|
-
# # If the record has been annotated by the
|
667
|
-
# # kubernetes_metadata_filter
|
668
|
-
# # plugin, then use that metadata. Otherwise, rely on
|
669
|
-
# # commonLabels
|
670
|
-
# # populated at the grouped_entries level from the group's tag.
|
671
|
-
# if record.key?('kubernetes')
|
672
|
-
# handle_container_metadata(record, entry)
|
673
|
-
# end
|
674
|
-
#
|
675
|
-
# # Save the timestamp if available, then clear it out to allow
|
676
|
-
# # for determining whether we should parse the log or message
|
677
|
-
# # field.
|
678
|
-
# timestamp = record.key?('time') ? record['time'] : nil
|
679
|
-
# record.delete('time')
|
680
|
-
# # If the log is json, we want to export it as a structured log
|
681
|
-
# # unless there is additional metadata that would be lost.
|
682
|
-
# is_json = false
|
683
|
-
# if record.length == 1 && record.key?('log')
|
684
|
-
# record_json = parse_json_or_nil(record['log'])
|
685
|
-
# end
|
686
|
-
# if record.length == 1 && record.key?('message')
|
687
|
-
# record_json = parse_json_or_nil(record['message'])
|
688
|
-
# end
|
689
|
-
# unless record_json.nil?
|
690
|
-
# record = record_json
|
691
|
-
# is_json = true
|
692
|
-
# end
|
693
|
-
# # Restore timestamp if necessary.
|
694
|
-
# unless record.key?('time') || timestamp.nil?
|
695
|
-
# record['time'] = timestamp
|
696
|
-
# end
|
697
|
-
# end
|
698
|
-
#
|
699
|
-
# ts_secs, ts_nanos = compute_timestamp(record, time)
|
700
|
-
# entry.metadata.timestamp = Google::Protobuf::Timestamp.new(
|
701
|
-
# seconds: ts_secs,
|
702
|
-
# nanos: ts_nanos
|
703
|
-
# )
|
704
|
-
#
|
705
|
-
# entry.metadata.severity =
|
706
|
-
# grpc_severity(compute_severity(record, entry))
|
707
|
-
#
|
708
|
-
# set_http_request_grpc(record, entry) # FIXME
|
709
|
-
#
|
710
|
-
# # If a field is present in the label_map, send its value as a
|
711
|
-
# # label
|
712
|
-
# # (mapping the field name to label name as specified in the
|
713
|
-
# # config)
|
714
|
-
# # and do not send that field as part of the payload.
|
715
|
-
# if @label_map
|
716
|
-
# @label_map.each do |field, label|
|
717
|
-
# field_to_label(record, field, entry.metadata.labels, label)
|
718
|
-
# end
|
719
|
-
# end
|
720
|
-
#
|
721
|
-
# if @service_name == CLOUDFUNCTIONS_SERVICE &&
|
722
|
-
# @cloudfunctions_log_match &&
|
723
|
-
# @cloudfunctions_log_match['execution_id']
|
724
|
-
# entry.metadata.labels['execution_id'] =
|
725
|
-
# @cloudfunctions_log_match['execution_id']
|
726
|
-
# end
|
727
|
-
#
|
728
|
-
# set_payload_grpc(record, entry, is_json)
|
729
|
-
#
|
730
|
-
# entries.push(entry)
|
731
|
-
# end
|
732
|
-
# # Don't send an empty request if we rejected all the entries.
|
733
|
-
# next if entries.empty?
|
734
|
-
#
|
735
|
-
# log_name = log_name(tag, labels)
|
736
|
-
#
|
737
|
-
# begin
|
738
|
-
# # Does the actual write to the cloud logging api.
|
739
|
-
#
|
740
|
-
# client = api_client
|
741
|
-
#
|
742
|
-
# labels_utf8_pairs = labels.map do |k, v|
|
743
|
-
# [k.encode('utf-8'), v.encode('utf-8')]
|
744
|
-
# end
|
745
|
-
#
|
746
|
-
# write_request = Google::Logging::V1::WriteLogEntriesRequest.new(
|
747
|
-
# log_name: log_name.encode('utf-8'),
|
748
|
-
# common_labels: Hash[labels_utf8_pairs],
|
749
|
-
# entries: entries
|
750
|
-
# )
|
751
|
-
#
|
752
|
-
# client.write_log_entries(write_request)
|
753
|
-
#
|
754
|
-
# # Let the user explicitly know when the first call succeeded,
|
755
|
-
# # to aid with verification and troubleshooting.
|
756
|
-
# unless @successful_call
|
757
|
-
# @successful_call = true
|
758
|
-
# @log.info 'Successfully sent gRPC to Stackdriver Logging API.'
|
759
|
-
# end
|
760
|
-
#
|
761
|
-
# rescue GRPC::Cancelled => error
|
762
|
-
# # RPC cancelled, so retry via re-raising the error.
|
763
|
-
# raise error
|
764
|
-
#
|
765
|
-
# rescue GRPC::BadStatus => error
|
766
|
-
# case error.code
|
767
|
-
# when GRPC::Core::StatusCodes::CANCELLED,
|
768
|
-
# GRPC::Core::StatusCodes::UNAVAILABLE,
|
769
|
-
# GRPC::Core::StatusCodes::DEADLINE_EXCEEDED,
|
770
|
-
# GRPC::Core::StatusCodes::INTERNAL,
|
771
|
-
# GRPC::Core::StatusCodes::UNKNOWN
|
772
|
-
# # TODO
|
773
|
-
# # Server error, so retry via re-raising the error.
|
774
|
-
# raise error
|
775
|
-
# when GRPC::Core::StatusCodes::UNIMPLEMENTED,
|
776
|
-
# GRPC::Core::StatusCodes::RESOURCE_EXHAUSTED
|
777
|
-
# # Most client errors indicate a problem with the request itself
|
778
|
-
# # and should not be retried.
|
779
|
-
# dropped = entries.length
|
780
|
-
# @log.warn "Dropping #{dropped} log message(s)",
|
781
|
-
# error: error.to_s, error_code: error.code.to_s
|
782
|
-
# when GRPC::Core::StatusCodes::UNAUTHENTICATED
|
783
|
-
# # Authorization error.
|
784
|
-
# # These are usually solved via a `gcloud auth` call, or by
|
785
|
-
# # modifying the permissions on the Google Cloud project.
|
786
|
-
# dropped = entries.length
|
787
|
-
# @log.warn "Dropping #{dropped} log message(s)",
|
788
|
-
# error: error.to_s, error_code: error.code.to_s
|
789
|
-
# else
|
790
|
-
# @log.error "Unknown response code #{error.code} from the " \
|
791
|
-
# "server",
|
792
|
-
# error: error.to_s, error_code: error.code.to_s
|
793
|
-
# end
|
794
|
-
# end
|
795
|
-
# else
|
796
|
-
# arr.each do |time, record|
|
797
|
-
# next unless record.is_a?(Hash)
|
798
|
-
#
|
799
|
-
# entry = Google::Apis::LoggingV1beta3::LogEntry.new(
|
800
|
-
# metadata: Google::Apis::LoggingV1beta3::LogEntryMetadata.new(
|
801
|
-
# service_name: @service_name,
|
802
|
-
# project_id: @project_id,
|
803
|
-
# zone: @zone,
|
804
|
-
# labels: {}
|
805
|
-
# ))
|
806
|
-
#
|
807
|
-
# if @service_name == CLOUDFUNCTIONS_SERVICE && record.key?('log')
|
808
|
-
# @cloudfunctions_log_match =
|
809
|
-
# @cloudfunctions_log_regexp.match(record['log'])
|
810
|
-
# end
|
811
|
-
# if @service_name == CONTAINER_SERVICE
|
812
|
-
# # Move the stdout/stderr annotation from the record into a label
|
813
|
-
# field_to_label(record, 'stream', entry.metadata.labels,
|
814
|
-
# "#{CONTAINER_SERVICE}/stream")
|
815
|
-
# # If the record has been annotated by the
|
816
|
-
# # kubernetes_metadata_filter
|
817
|
-
# # plugin, then use that metadata. Otherwise, rely on
|
818
|
-
# # commonLabels
|
819
|
-
# # populated at the grouped_entries level from the group's tag.
|
820
|
-
# if record.key?('kubernetes')
|
821
|
-
# handle_container_metadata(record, entry)
|
822
|
-
# end
|
823
|
-
#
|
824
|
-
# # Save the timestamp if available, then clear it out to allow
|
825
|
-
# # for determining whether we should parse the log or message
|
826
|
-
# # field.
|
827
|
-
# timestamp = record.key?('time') ? record['time'] : nil
|
828
|
-
# record.delete('time')
|
829
|
-
# # If the log is json, we want to export it as a structured log
|
830
|
-
# # unless there is additional metadata that would be lost.
|
831
|
-
# is_json = false
|
832
|
-
# if record.length == 1 && record.key?('log')
|
833
|
-
# record_json = parse_json_or_nil(record['log'])
|
834
|
-
# end
|
835
|
-
# if record.length == 1 && record.key?('message')
|
836
|
-
# record_json = parse_json_or_nil(record['message'])
|
837
|
-
# end
|
838
|
-
# unless record_json.nil?
|
839
|
-
# record = record_json
|
840
|
-
# is_json = true
|
841
|
-
# end
|
842
|
-
# # Restore timestamp if necessary.
|
843
|
-
# unless record.key?('time') || timestamp.nil?
|
844
|
-
# record['time'] = timestamp
|
845
|
-
# end
|
846
|
-
# end
|
847
|
-
#
|
848
|
-
# ts_secs, ts_nanos = compute_timestamp(record, time)
|
849
|
-
# entry.metadata.timestamp = {
|
850
|
-
# seconds: ts_secs,
|
851
|
-
# nanos: ts_nanos
|
852
|
-
# }
|
853
|
-
#
|
854
|
-
# entry.metadata.severity = compute_severity(record, entry)
|
855
|
-
#
|
856
|
-
# set_http_request(record, entry)
|
857
|
-
#
|
858
|
-
# # If a field is present in the label_map, send its value as a
|
859
|
-
# # label
|
860
|
-
# # (mapping the field name to label name as specified in the
|
861
|
-
# # config)
|
862
|
-
# # and do not send that field as part of the payload.
|
863
|
-
# if @label_map
|
864
|
-
# @label_map.each do |field, label|
|
865
|
-
# field_to_label(record, field, entry.metadata.labels, label)
|
866
|
-
# end
|
867
|
-
# end
|
868
|
-
#
|
869
|
-
# if @service_name == CLOUDFUNCTIONS_SERVICE &&
|
870
|
-
# @cloudfunctions_log_match &&
|
871
|
-
# @cloudfunctions_log_match['execution_id']
|
872
|
-
# entry.metadata.labels['execution_id'] =
|
873
|
-
# @cloudfunctions_log_match['execution_id']
|
874
|
-
# end
|
875
|
-
#
|
876
|
-
# set_payload(record, entry, is_json)
|
877
|
-
# entry.metadata.labels = nil if entry.metadata.labels.empty?
|
878
|
-
#
|
879
|
-
# entries.push(entry)
|
880
|
-
# end
|
881
|
-
# # Don't send an empty request if we rejected all the entries.
|
882
|
-
# next if entries.empty?
|
883
|
-
#
|
884
|
-
# log_name = log_name(tag, labels)
|
885
|
-
#
|
886
|
-
# begin
|
887
|
-
# # Does the actual write to the cloud logging api.
|
888
|
-
# # The URI of the write is constructed by the Google::Api request;
|
889
|
-
# # it is equivalent to this URL:
|
890
|
-
# # 'https://logging.googleapis.com/v1beta3/projects/' \
|
891
|
-
# # "#{@project_id}/logs/#{log_name}/entries:write"
|
892
|
-
#
|
893
|
-
# client = api_client
|
894
|
-
#
|
895
|
-
# write_request = \
|
896
|
-
# Google::Apis::LoggingV1beta3::WriteLogEntriesRequest.new(
|
897
|
-
# common_labels: labels,
|
898
|
-
# entries: entries)
|
899
|
-
#
|
900
|
-
# # TODO: RequestOptions
|
901
|
-
# client.write_log_entries(@project_id, log_name, write_request)
|
902
|
-
#
|
903
|
-
# # Let the user explicitly know when the first call succeeded,
|
904
|
-
# # to aid with verification and troubleshooting.
|
905
|
-
# unless @successful_call
|
906
|
-
# @successful_call = true
|
907
|
-
# @log.info 'Successfully sent to Stackdriver Logging API.'
|
908
|
-
# end
|
909
|
-
#
|
910
|
-
# rescue Google::Apis::ServerError => error
|
911
|
-
# # Server error, so retry via re-raising the error.
|
912
|
-
# raise error
|
913
|
-
#
|
914
|
-
# rescue Google::Apis::AuthorizationError => error
|
915
|
-
# # Authorization error.
|
916
|
-
# # These are usually solved via a `gcloud auth` call, or by
|
917
|
-
# # modifying
|
918
|
-
# # the permissions on the Google Cloud project.
|
919
|
-
# dropped = entries.length
|
920
|
-
# @log.warn "Dropping #{dropped} log message(s)",
|
921
|
-
# error_class: error.class.to_s, error: error.to_s
|
922
|
-
#
|
923
|
-
# rescue Google::Apis::ClientError => error
|
924
|
-
# # Most ClientErrors indicate a problem with the request itself and
|
925
|
-
# # should not be retried.
|
926
|
-
# dropped = entries.length
|
927
|
-
# @log.warn "Dropping #{dropped} log message(s)",
|
928
|
-
# error_class: error.class.to_s, error: error.to_s
|
929
|
-
# end
|
930
|
-
# end
|
931
|
-
# end
|
932
|
-
# end
|
933
|
-
|
934
602
|
private
|
935
603
|
|
936
604
|
def parse_json_or_nil(input)
|
@@ -1159,27 +827,32 @@ module Fluent
|
|
1159
827
|
return nil unless record['httpRequest'].is_a?(Hash)
|
1160
828
|
input = record['httpRequest']
|
1161
829
|
output = Google::Logging::Type::HttpRequest.new
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
output.
|
1167
|
-
|
1168
|
-
output.
|
1169
|
-
|
1170
|
-
output.
|
1171
|
-
|
1172
|
-
output.
|
1173
|
-
|
1174
|
-
output.
|
1175
|
-
|
1176
|
-
output.
|
1177
|
-
|
1178
|
-
output.
|
1179
|
-
|
830
|
+
# We need to delete each field from 'httpRequest' even if its value is
|
831
|
+
# nil. However we do not want to assign this nil value to proto fields
|
832
|
+
# defined as strings / integers.
|
833
|
+
request_method = input.delete('requestMethod')
|
834
|
+
output.request_method = request_method unless request_method.nil?
|
835
|
+
request_url = input.delete('requestUrl')
|
836
|
+
output.request_url = request_url unless request_url.nil?
|
837
|
+
request_size = input.delete('requestSize')
|
838
|
+
output.request_size = request_size.to_i unless request_size.nil?
|
839
|
+
status = input.delete('status')
|
840
|
+
output.status = status.to_i unless status.nil?
|
841
|
+
response_size = input.delete('responseSize')
|
842
|
+
output.response_size = response_size.to_i unless response_size.nil?
|
843
|
+
user_agent = input.delete('userAgent')
|
844
|
+
output.user_agent = user_agent unless user_agent.nil?
|
845
|
+
remote_ip = input.delete('remoteIp')
|
846
|
+
output.remote_ip = remote_ip unless remote_ip.nil?
|
847
|
+
referer = input.delete('referer')
|
848
|
+
output.referer = referer unless referer.nil?
|
849
|
+
cache_hit = input.delete('cacheHit')
|
850
|
+
output.cache_hit = cache_hit unless cache_hit.nil?
|
851
|
+
cache_validated_with_origin_server = \
|
852
|
+
input.delete('cacheValidatedWithOriginServer')
|
1180
853
|
output.cache_validated_with_origin_server = \
|
1181
|
-
|
1182
|
-
|
854
|
+
cache_validated_with_origin_server \
|
855
|
+
unless cache_validated_with_origin_server.nil?
|
1183
856
|
record.delete('httpRequest') if input.empty?
|
1184
857
|
entry.http_request = output
|
1185
858
|
end
|
data/test/plugin/base_test.rb
CHANGED
@@ -307,6 +307,19 @@ module BaseTest
|
|
307
307
|
}
|
308
308
|
}
|
309
309
|
|
310
|
+
HTTP_REQUEST_MESSAGE = {
|
311
|
+
'requestMethod' => 'POST',
|
312
|
+
'requestUrl' => 'http://example/',
|
313
|
+
'requestSize' => 210,
|
314
|
+
'status' => 200,
|
315
|
+
'responseSize' => 65,
|
316
|
+
'userAgent' => 'USER AGENT 1.0',
|
317
|
+
'remoteIp' => '55.55.55.55',
|
318
|
+
'referer' => 'http://referer/',
|
319
|
+
'cacheHit' => true,
|
320
|
+
'cacheValidatedWithOriginServer' => true
|
321
|
+
}
|
322
|
+
|
310
323
|
# Shared tests.
|
311
324
|
|
312
325
|
def test_configure_service_account_application_default
|
@@ -517,15 +530,17 @@ module BaseTest
|
|
517
530
|
setup_gce_metadata_stubs
|
518
531
|
setup_logging_stubs do
|
519
532
|
d = create_driver
|
520
|
-
d.emit('msg' => log_entry(0), 'tag2' => 'test', 'data' => 5000
|
533
|
+
d.emit('msg' => log_entry(0), 'tag2' => 'test', 'data' => 5000,
|
534
|
+
'some_null_field' => nil)
|
521
535
|
d.run
|
522
536
|
end
|
523
537
|
verify_log_entries(1, COMPUTE_PARAMS, 'structPayload') do |entry|
|
524
538
|
fields = get_fields(entry['structPayload'])
|
525
|
-
assert_equal
|
539
|
+
assert_equal 4, fields.size, entry
|
526
540
|
assert_equal 'test log entry 0', get_string(fields['msg']), entry
|
527
541
|
assert_equal 'test', get_string(fields['tag2']), entry
|
528
542
|
assert_equal 5000, get_number(fields['data']), entry
|
543
|
+
assert_equal null_value, fields['some_null_field'], entry
|
529
544
|
end
|
530
545
|
end
|
531
546
|
|
@@ -550,7 +565,8 @@ module BaseTest
|
|
550
565
|
setup_container_metadata_stubs
|
551
566
|
setup_logging_stubs do
|
552
567
|
d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
|
553
|
-
json_string = '{"msg": "test log entry 0", "tag2": "test",
|
568
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", ' \
|
569
|
+
'"data": 5000, "some_null_field": null}'
|
554
570
|
d.emit(container_log_entry_with_metadata('notJSON' + json_string))
|
555
571
|
d.emit(container_log_entry_with_metadata(json_string))
|
556
572
|
d.emit(container_log_entry_with_metadata(" \r\n \t" + json_string))
|
@@ -565,10 +581,11 @@ module BaseTest
|
|
565
581
|
else
|
566
582
|
assert entry.key?('structPayload'), 'Entry did not have structPayload'
|
567
583
|
fields = get_fields(entry['structPayload'])
|
568
|
-
assert_equal
|
584
|
+
assert_equal 4, fields.size, entry
|
569
585
|
assert_equal 'test log entry 0', get_string(fields['msg']), entry
|
570
586
|
assert_equal 'test', get_string(fields['tag2']), entry
|
571
587
|
assert_equal 5000, get_number(fields['data']), entry
|
588
|
+
assert_equal null_value, fields['some_null_field'], entry
|
572
589
|
end
|
573
590
|
end
|
574
591
|
end
|
@@ -1025,20 +1042,6 @@ module BaseTest
|
|
1025
1042
|
end
|
1026
1043
|
end
|
1027
1044
|
|
1028
|
-
def test_http_request_without_referer_from_record
|
1029
|
-
setup_gce_metadata_stubs
|
1030
|
-
setup_logging_stubs do
|
1031
|
-
d = create_driver
|
1032
|
-
d.emit('httpRequest' => http_request_message_without_referer)
|
1033
|
-
d.run
|
1034
|
-
end
|
1035
|
-
verify_log_entries(1, COMPUTE_PARAMS, 'httpRequest') do |entry|
|
1036
|
-
assert_equal http_request_message_without_referer, entry['httpRequest'],
|
1037
|
-
entry
|
1038
|
-
assert_nil get_fields(entry['structPayload'])['httpRequest'], entry
|
1039
|
-
end
|
1040
|
-
end
|
1041
|
-
|
1042
1045
|
def test_http_request_when_not_hash
|
1043
1046
|
setup_gce_metadata_stubs
|
1044
1047
|
setup_logging_stubs do
|
@@ -1241,6 +1244,16 @@ module BaseTest
|
|
1241
1244
|
assert i == n, "Number of entries #{i} does not match expected number #{n}"
|
1242
1245
|
end
|
1243
1246
|
|
1247
|
+
# The http request message to test against.
|
1248
|
+
def http_request_message
|
1249
|
+
HTTP_REQUEST_MESSAGE
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
# Replace the 'referer' field with nil.
|
1253
|
+
def http_request_message_with_nil_referer
|
1254
|
+
http_request_message.merge('referer' => nil)
|
1255
|
+
end
|
1256
|
+
|
1244
1257
|
# This module expects the methods below to be overridden.
|
1245
1258
|
|
1246
1259
|
# Create a Fluentd output test driver with the Google Cloud Output plugin.
|
@@ -1269,19 +1282,6 @@ module BaseTest
|
|
1269
1282
|
_undefined
|
1270
1283
|
end
|
1271
1284
|
|
1272
|
-
# A wrapper around the constant HTTP_REQUEST_MESSAGE, so the definition can be
|
1273
|
-
# skipped in the shared module here and defined in the test class later.
|
1274
|
-
def http_request_message
|
1275
|
-
_undefined
|
1276
|
-
end
|
1277
|
-
|
1278
|
-
# A wrapper around the constant HTTP_REQUEST_MESSAGE_WITHOUT_REFERER, so the
|
1279
|
-
# definition can be skipped in the shared module and defined in the test
|
1280
|
-
# classes later.
|
1281
|
-
def http_request_message_without_referer
|
1282
|
-
_undefined
|
1283
|
-
end
|
1284
|
-
|
1285
1285
|
# Get the fields of the struct payload.
|
1286
1286
|
def get_fields(_struct_payload)
|
1287
1287
|
_undefined
|
@@ -1302,6 +1302,11 @@ module BaseTest
|
|
1302
1302
|
_undefined
|
1303
1303
|
end
|
1304
1304
|
|
1305
|
+
# The null value.
|
1306
|
+
def null_value(_field)
|
1307
|
+
_undefined
|
1308
|
+
end
|
1309
|
+
|
1305
1310
|
def _undefined
|
1306
1311
|
fail "Method #{__callee__} is unimplemented and needs to be overridden."
|
1307
1312
|
end
|
@@ -70,6 +70,24 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
70
70
|
assert_equal 1, exception_count
|
71
71
|
end
|
72
72
|
|
73
|
+
def test_http_request_from_record_with_referer_nil
|
74
|
+
setup_gce_metadata_stubs
|
75
|
+
setup_logging_stubs do
|
76
|
+
d = create_driver
|
77
|
+
d.emit('httpRequest' => http_request_message_with_nil_referer)
|
78
|
+
d.run
|
79
|
+
end
|
80
|
+
verify_log_entries(1, COMPUTE_PARAMS, 'httpRequest') do |entry|
|
81
|
+
# The request we send to Logging API has json like:
|
82
|
+
# "httpRequest": { "referer": null }, but eventually the stored LogEntry
|
83
|
+
# would be "httpRequest": {}, since 'referer' is defined as a string in
|
84
|
+
# the proto.
|
85
|
+
assert_equal http_request_message_with_nil_referer,
|
86
|
+
entry['httpRequest'], entry
|
87
|
+
assert_nil get_fields(entry['structPayload'])['httpRequest'], entry
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
73
91
|
# This test looks similar between the grpc and non-grpc paths except that when
|
74
92
|
# parsing "105", the grpc path responds with "DEBUG", while the non-grpc path
|
75
93
|
# responds with "100".
|
@@ -175,25 +193,16 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
175
193
|
|
176
194
|
private
|
177
195
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
'
|
186
|
-
|
187
|
-
|
188
|
-
'referer' => 'http://referer/',
|
189
|
-
'cacheHit' => false,
|
190
|
-
'validatedWithOriginServer' => true
|
191
|
-
}
|
192
|
-
|
193
|
-
# In the non-grpc path 'referer' is nil, while in the grpc path 'referer' is
|
194
|
-
# absent.
|
195
|
-
HTTP_REQUEST_MESSAGE_WITHOUT_REFERER = HTTP_REQUEST_MESSAGE.merge(
|
196
|
-
'referer' => nil)
|
196
|
+
def rename_key(hash, old_key, new_key)
|
197
|
+
hash.merge(new_key => hash[old_key]).reject { |k, _| k == old_key }
|
198
|
+
end
|
199
|
+
|
200
|
+
# The REST path uses old bindings that were generated prior to the field
|
201
|
+
# rename, and has to use the old name, which is 'validatedWithOriginServer'.
|
202
|
+
def http_request_message
|
203
|
+
rename_key(super, 'cacheValidatedWithOriginServer',
|
204
|
+
'validatedWithOriginServer')
|
205
|
+
end
|
197
206
|
|
198
207
|
# Set up http stubs to mock the external calls.
|
199
208
|
def setup_logging_stubs
|
@@ -234,18 +243,6 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
234
243
|
end
|
235
244
|
end
|
236
245
|
|
237
|
-
# A wrapper around the constant HTTP_REQUEST_MESSAGE, so the definition can be
|
238
|
-
# skipped in the shared module and defined here.
|
239
|
-
def http_request_message
|
240
|
-
HTTP_REQUEST_MESSAGE
|
241
|
-
end
|
242
|
-
|
243
|
-
# A wrapper around the constant HTTP_REQUEST_MESSAGE_WITHOUT_REFERER, so the
|
244
|
-
# definition can be skipped in the shared module and defined here.
|
245
|
-
def http_request_message_without_referer
|
246
|
-
HTTP_REQUEST_MESSAGE_WITHOUT_REFERER
|
247
|
-
end
|
248
|
-
|
249
246
|
# Get the fields of the struct payload.
|
250
247
|
def get_fields(struct_payload)
|
251
248
|
struct_payload
|
@@ -265,4 +262,9 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
265
262
|
def get_number(field)
|
266
263
|
field
|
267
264
|
end
|
265
|
+
|
266
|
+
# The null value.
|
267
|
+
def null_value
|
268
|
+
nil
|
269
|
+
end
|
268
270
|
end
|
@@ -72,6 +72,34 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
+
def test_http_request_from_record_with_referer_nil
|
76
|
+
setup_gce_metadata_stubs
|
77
|
+
setup_logging_stubs do
|
78
|
+
d = create_driver
|
79
|
+
d.emit('httpRequest' => http_request_message_with_nil_referer)
|
80
|
+
d.run
|
81
|
+
end
|
82
|
+
verify_log_entries(1, COMPUTE_PARAMS, 'httpRequest') do |entry|
|
83
|
+
assert_equal http_request_message_with_absent_referer,
|
84
|
+
entry['httpRequest'], entry
|
85
|
+
assert_nil get_fields(entry['structPayload'])['httpRequest'], entry
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_http_request_from_record_with_referer_absent
|
90
|
+
setup_gce_metadata_stubs
|
91
|
+
setup_logging_stubs do
|
92
|
+
d = create_driver
|
93
|
+
d.emit('httpRequest' => http_request_message_with_absent_referer)
|
94
|
+
d.run
|
95
|
+
end
|
96
|
+
verify_log_entries(1, COMPUTE_PARAMS, 'httpRequest') do |entry|
|
97
|
+
assert_equal http_request_message_with_absent_referer,
|
98
|
+
entry['httpRequest'], entry
|
99
|
+
assert_nil get_fields(entry['structPayload'])['httpRequest'], entry
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
75
103
|
# This test looks similar between the grpc and non-grpc paths except that when
|
76
104
|
# parsing "105", the grpc path responds with "DEBUG", while the non-grpc path
|
77
105
|
# responds with "100".
|
@@ -114,27 +142,6 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
114
142
|
use_grpc true
|
115
143
|
)
|
116
144
|
|
117
|
-
# The non-grpc path has a unique field 'validatedWithOriginServer', while
|
118
|
-
# the grpc path has a unique field 'cacheValidatedWithOriginServer'.
|
119
|
-
HTTP_REQUEST_MESSAGE = {
|
120
|
-
'requestMethod' => 'POST',
|
121
|
-
'requestUrl' => 'http://example/',
|
122
|
-
'requestSize' => 210,
|
123
|
-
'status' => 200,
|
124
|
-
'responseSize' => 65,
|
125
|
-
'userAgent' => 'USER AGENT 1.0',
|
126
|
-
'remoteIp' => '55.55.55.55',
|
127
|
-
'referer' => 'http://referer/',
|
128
|
-
'cacheHit' => true,
|
129
|
-
'cacheValidatedWithOriginServer' => true
|
130
|
-
}
|
131
|
-
|
132
|
-
# In the non-grpc path 'referer' is nil, while in the grpc path 'referer' is
|
133
|
-
# absent.
|
134
|
-
HTTP_REQUEST_MESSAGE_WITHOUT_REFERER = HTTP_REQUEST_MESSAGE.reject do |k, _|
|
135
|
-
k == 'referer'
|
136
|
-
end
|
137
|
-
|
138
145
|
# Create a Fluentd output test driver with the Google Cloud Output plugin with
|
139
146
|
# grpc enabled. The signature of this method is different between the grpc
|
140
147
|
# path and the non-grpc path. For grpc, an additional grpc stub class can be
|
@@ -275,16 +282,11 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
275
282
|
end
|
276
283
|
end
|
277
284
|
|
278
|
-
#
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
# A wrapper around the constant HTTP_REQUEST_MESSAGE_WITHOUT_REFERER, so the
|
285
|
-
# definition can be skipped in the shared module and defined here.
|
286
|
-
def http_request_message_without_referer
|
287
|
-
HTTP_REQUEST_MESSAGE_WITHOUT_REFERER
|
285
|
+
# Unset the 'referer' field.
|
286
|
+
def http_request_message_with_absent_referer
|
287
|
+
http_request_message.reject do |k, _|
|
288
|
+
k == 'referer'
|
289
|
+
end
|
288
290
|
end
|
289
291
|
|
290
292
|
# Get the fields of the struct payload.
|
@@ -306,4 +308,9 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
306
308
|
def get_number(field)
|
307
309
|
field['numberValue']
|
308
310
|
end
|
311
|
+
|
312
|
+
# The null value.
|
313
|
+
def null_value
|
314
|
+
{ 'nullValue' => 'NULL_VALUE' }
|
315
|
+
end
|
309
316
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-google-cloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.3.grpc.alpha.
|
4
|
+
version: 0.5.3.grpc.alpha.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Todd Derr
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-12-
|
12
|
+
date: 2016-12-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|