logstash-output-google_cloud_storage 4.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +77 -0
  3. data/CONTRIBUTORS +18 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE +13 -0
  6. data/NOTICE.TXT +5 -0
  7. data/README.md +100 -0
  8. data/docs/index.asciidoc +305 -0
  9. data/lib/logstash-output-google_cloud_storage_jars.rb +35 -0
  10. data/lib/logstash/outputs/gcs/client.rb +88 -0
  11. data/lib/logstash/outputs/gcs/log_rotate.rb +77 -0
  12. data/lib/logstash/outputs/gcs/path_factory.rb +119 -0
  13. data/lib/logstash/outputs/gcs/temp_log_file.rb +111 -0
  14. data/lib/logstash/outputs/gcs/worker_pool.rb +47 -0
  15. data/lib/logstash/outputs/google_cloud_storage.rb +276 -0
  16. data/logstash-output-google_cloud_storage.gemspec +33 -0
  17. data/spec/fixtures/credentials.json +8 -0
  18. data/spec/outputs/gcs/client_spec.rb +18 -0
  19. data/spec/outputs/gcs/log_rotate_spec.rb +129 -0
  20. data/spec/outputs/gcs/path_factory_spec.rb +189 -0
  21. data/spec/outputs/gcs/temp_log_file_spec.rb +155 -0
  22. data/spec/outputs/gcs/worker_pool_spec.rb +29 -0
  23. data/spec/outputs/google_cloud_storage_spec.rb +23 -0
  24. data/spec/spec_helper.rb +3 -0
  25. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-core/2.9.6/jackson-core-2.9.6.jar +0 -0
  26. data/vendor/jar-dependencies/com/google/api-client/google-api-client/1.23.0/google-api-client-1.23.0.jar +0 -0
  27. data/vendor/jar-dependencies/com/google/api-client/google-api-client/1.24.1/google-api-client-1.24.1.jar +0 -0
  28. data/vendor/jar-dependencies/com/google/api-client/google-api-client/1.27.0/google-api-client-1.27.0.jar +0 -0
  29. data/vendor/jar-dependencies/com/google/api/api-common/1.5.0/api-common-1.5.0.jar +0 -0
  30. data/vendor/jar-dependencies/com/google/api/api-common/1.7.0/api-common-1.7.0.jar +0 -0
  31. data/vendor/jar-dependencies/com/google/api/gax-httpjson/0.40.0/gax-httpjson-0.40.0.jar +0 -0
  32. data/vendor/jar-dependencies/com/google/api/gax-httpjson/0.47.0/gax-httpjson-0.47.0.jar +0 -0
  33. data/vendor/jar-dependencies/com/google/api/gax-httpjson/0.59.0/gax-httpjson-0.59.0.jar +0 -0
  34. data/vendor/jar-dependencies/com/google/api/gax/1.23.0/gax-1.23.0.jar +0 -0
  35. data/vendor/jar-dependencies/com/google/api/gax/1.30.0/gax-1.30.0.jar +0 -0
  36. data/vendor/jar-dependencies/com/google/api/gax/1.42.0/gax-1.42.0.jar +0 -0
  37. data/vendor/jar-dependencies/com/google/api/grpc/proto-google-common-protos/1.12.0/proto-google-common-protos-1.12.0.jar +0 -0
  38. data/vendor/jar-dependencies/com/google/api/grpc/proto-google-common-protos/1.14.0/proto-google-common-protos-1.14.0.jar +0 -0
  39. data/vendor/jar-dependencies/com/google/api/grpc/proto-google-common-protos/1.7.0/proto-google-common-protos-1.7.0.jar +0 -0
  40. data/vendor/jar-dependencies/com/google/api/grpc/proto-google-iam-v1/0.12.0/proto-google-iam-v1-0.12.0.jar +0 -0
  41. data/vendor/jar-dependencies/com/google/api/grpc/proto-google-iam-v1/0.8.0/proto-google-iam-v1-0.8.0.jar +0 -0
  42. data/vendor/jar-dependencies/com/google/apis/google-api-services-storage/v1-rev114-1.23.0/google-api-services-storage-v1-rev114-1.23.0.jar +0 -0
  43. data/vendor/jar-dependencies/com/google/apis/google-api-services-storage/v1-rev135-1.24.1/google-api-services-storage-v1-rev135-1.24.1.jar +0 -0
  44. data/vendor/jar-dependencies/com/google/apis/google-api-services-storage/v1-rev20181109-1.27.0/google-api-services-storage-v1-rev20181109-1.27.0.jar +0 -0
  45. data/vendor/jar-dependencies/com/google/auth/google-auth-library-credentials/0.10.0/google-auth-library-credentials-0.10.0.jar +0 -0
  46. data/vendor/jar-dependencies/com/google/auth/google-auth-library-credentials/0.13.0/google-auth-library-credentials-0.13.0.jar +0 -0
  47. data/vendor/jar-dependencies/com/google/auth/google-auth-library-credentials/0.9.0/google-auth-library-credentials-0.9.0.jar +0 -0
  48. data/vendor/jar-dependencies/com/google/auth/google-auth-library-oauth2-http/0.10.0/google-auth-library-oauth2-http-0.10.0.jar +0 -0
  49. data/vendor/jar-dependencies/com/google/auth/google-auth-library-oauth2-http/0.13.0/google-auth-library-oauth2-http-0.13.0.jar +0 -0
  50. data/vendor/jar-dependencies/com/google/auth/google-auth-library-oauth2-http/0.9.0/google-auth-library-oauth2-http-0.9.0.jar +0 -0
  51. data/vendor/jar-dependencies/com/google/cloud/google-cloud-core-http/1.25.0/google-cloud-core-http-1.25.0.jar +0 -0
  52. data/vendor/jar-dependencies/com/google/cloud/google-cloud-core-http/1.39.0/google-cloud-core-http-1.39.0.jar +0 -0
  53. data/vendor/jar-dependencies/com/google/cloud/google-cloud-core-http/1.65.0/google-cloud-core-http-1.65.0.jar +0 -0
  54. data/vendor/jar-dependencies/com/google/cloud/google-cloud-core/1.25.0/google-cloud-core-1.25.0.jar +0 -0
  55. data/vendor/jar-dependencies/com/google/cloud/google-cloud-core/1.39.0/google-cloud-core-1.39.0.jar +0 -0
  56. data/vendor/jar-dependencies/com/google/cloud/google-cloud-core/1.65.0/google-cloud-core-1.65.0.jar +0 -0
  57. data/vendor/jar-dependencies/com/google/cloud/google-cloud-storage/1.25.0/google-cloud-storage-1.25.0.jar +0 -0
  58. data/vendor/jar-dependencies/com/google/cloud/google-cloud-storage/1.39.0/google-cloud-storage-1.39.0.jar +0 -0
  59. data/vendor/jar-dependencies/com/google/cloud/google-cloud-storage/1.65.0/google-cloud-storage-1.65.0.jar +0 -0
  60. data/vendor/jar-dependencies/com/google/code/findbugs/jsr305/3.0.1/jsr305-3.0.1.jar +0 -0
  61. data/vendor/jar-dependencies/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar +0 -0
  62. data/vendor/jar-dependencies/com/google/code/gson/gson/2.7/gson-2.7.jar +0 -0
  63. data/vendor/jar-dependencies/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3.jar +0 -0
  64. data/vendor/jar-dependencies/com/google/errorprone/error_prone_annotations/2.2.0/error_prone_annotations-2.2.0.jar +0 -0
  65. data/vendor/jar-dependencies/com/google/guava/guava-jdk5/17.0/guava-jdk5-17.0.jar +0 -0
  66. data/vendor/jar-dependencies/com/google/guava/guava/20.0/guava-20.0.jar +0 -0
  67. data/vendor/jar-dependencies/com/google/guava/guava/26.0-android/guava-26.0-android.jar +0 -0
  68. data/vendor/jar-dependencies/com/google/http-client/google-http-client-apache/2.0.0/google-http-client-apache-2.0.0.jar +0 -0
  69. data/vendor/jar-dependencies/com/google/http-client/google-http-client-appengine/1.23.0/google-http-client-appengine-1.23.0.jar +0 -0
  70. data/vendor/jar-dependencies/com/google/http-client/google-http-client-appengine/1.24.1/google-http-client-appengine-1.24.1.jar +0 -0
  71. data/vendor/jar-dependencies/com/google/http-client/google-http-client-appengine/1.28.0/google-http-client-appengine-1.28.0.jar +0 -0
  72. data/vendor/jar-dependencies/com/google/http-client/google-http-client-jackson/1.23.0/google-http-client-jackson-1.23.0.jar +0 -0
  73. data/vendor/jar-dependencies/com/google/http-client/google-http-client-jackson/1.24.1/google-http-client-jackson-1.24.1.jar +0 -0
  74. data/vendor/jar-dependencies/com/google/http-client/google-http-client-jackson2/1.23.0/google-http-client-jackson2-1.23.0.jar +0 -0
  75. data/vendor/jar-dependencies/com/google/http-client/google-http-client-jackson2/1.24.1/google-http-client-jackson2-1.24.1.jar +0 -0
  76. data/vendor/jar-dependencies/com/google/http-client/google-http-client-jackson2/1.28.0/google-http-client-jackson2-1.28.0.jar +0 -0
  77. data/vendor/jar-dependencies/com/google/http-client/google-http-client/1.23.0/google-http-client-1.23.0.jar +0 -0
  78. data/vendor/jar-dependencies/com/google/http-client/google-http-client/1.24.1/google-http-client-1.24.1.jar +0 -0
  79. data/vendor/jar-dependencies/com/google/http-client/google-http-client/1.28.0/google-http-client-1.28.0.jar +0 -0
  80. data/vendor/jar-dependencies/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar +0 -0
  81. data/vendor/jar-dependencies/com/google/oauth-client/google-oauth-client/1.23.0/google-oauth-client-1.23.0.jar +0 -0
  82. data/vendor/jar-dependencies/com/google/oauth-client/google-oauth-client/1.24.1/google-oauth-client-1.24.1.jar +0 -0
  83. data/vendor/jar-dependencies/com/google/oauth-client/google-oauth-client/1.27.0/google-oauth-client-1.27.0.jar +0 -0
  84. data/vendor/jar-dependencies/com/google/protobuf/protobuf-java-util/3.5.1/protobuf-java-util-3.5.1.jar +0 -0
  85. data/vendor/jar-dependencies/com/google/protobuf/protobuf-java-util/3.6.0/protobuf-java-util-3.6.0.jar +0 -0
  86. data/vendor/jar-dependencies/com/google/protobuf/protobuf-java/3.5.1/protobuf-java-3.5.1.jar +0 -0
  87. data/vendor/jar-dependencies/com/google/protobuf/protobuf-java/3.6.0/protobuf-java-3.6.0.jar +0 -0
  88. data/vendor/jar-dependencies/commons-codec/commons-codec/1.3/commons-codec-1.3.jar +0 -0
  89. data/vendor/jar-dependencies/commons-codec/commons-codec/1.9/commons-codec-1.9.jar +0 -0
  90. data/vendor/jar-dependencies/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar +0 -0
  91. data/vendor/jar-dependencies/commons-logging/commons-logging/1.2/commons-logging-1.2.jar +0 -0
  92. data/vendor/jar-dependencies/io/grpc/grpc-context/1.12.0/grpc-context-1.12.0.jar +0 -0
  93. data/vendor/jar-dependencies/io/grpc/grpc-context/1.9.0/grpc-context-1.9.0.jar +0 -0
  94. data/vendor/jar-dependencies/io/opencensus/opencensus-api/0.11.1/opencensus-api-0.11.1.jar +0 -0
  95. data/vendor/jar-dependencies/io/opencensus/opencensus-api/0.15.0/opencensus-api-0.15.0.jar +0 -0
  96. data/vendor/jar-dependencies/io/opencensus/opencensus-contrib-http-util/0.11.1/opencensus-contrib-http-util-0.11.1.jar +0 -0
  97. data/vendor/jar-dependencies/io/opencensus/opencensus-contrib-http-util/0.15.0/opencensus-contrib-http-util-0.15.0.jar +0 -0
  98. data/vendor/jar-dependencies/joda-time/joda-time/2.9.2/joda-time-2.9.2.jar +0 -0
  99. data/vendor/jar-dependencies/org/apache/httpcomponents/httpclient/4.0.1/httpclient-4.0.1.jar +0 -0
  100. data/vendor/jar-dependencies/org/apache/httpcomponents/httpclient/4.5.3/httpclient-4.5.3.jar +0 -0
  101. data/vendor/jar-dependencies/org/apache/httpcomponents/httpcore/4.0.1/httpcore-4.0.1.jar +0 -0
  102. data/vendor/jar-dependencies/org/apache/httpcomponents/httpcore/4.4.6/httpcore-4.4.6.jar +0 -0
  103. data/vendor/jar-dependencies/org/codehaus/jackson/jackson-core-asl/1.9.11/jackson-core-asl-1.9.11.jar +0 -0
  104. data/vendor/jar-dependencies/org/threeten/threetenbp/1.3.3/threetenbp-1.3.3.jar +0 -0
  105. metadata +249 -0
@@ -0,0 +1,276 @@
1
+ # [source,txt]
2
+ # -----
3
+ # encoding: utf-8
4
+ # Author: Rodrigo De Castro <rdc@google.com>
5
+ # Date: 2013-09-20
6
+ #
7
+ # Copyright 2013 Google Inc.
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ # -----
21
+ require 'logstash/outputs/gcs/client'
22
+ require "logstash/outputs/base"
23
+ require "logstash/outputs/gcs/path_factory"
24
+ require "logstash/outputs/gcs/worker_pool"
25
+ require "logstash/outputs/gcs/log_rotate"
26
+ require "logstash/namespace"
27
+ require "logstash/json"
28
+ require "stud/interval"
29
+ require "thread"
30
+ require "zlib"
31
+
32
+ # Summary: plugin to upload log events to Google Cloud Storage (GCS), rolling
33
+ # files based on the date pattern provided as a configuration setting. Events
34
+ # are written to files locally and, once file is closed, this plugin uploads
35
+ # it to the configured bucket.
36
+ #
37
+ # For more info on Google Cloud Storage, please go to:
38
+ # https://cloud.google.com/products/cloud-storage
39
+ #
40
+ # In order to use this plugin, a Google service account must be used. For
41
+ # more information, please refer to:
42
+ # https://developers.google.com/storage/docs/authentication#service_accounts
43
+ #
44
+ # Recommendation: experiment with the settings depending on how much log
45
+ # data you generate, so the uploader can keep up with the generated logs.
46
+ # Using gzip output can be a good option to reduce network traffic when
47
+ # uploading the log files and in terms of storage costs as well.
48
+ #
49
+ # USAGE:
50
+ # This is an example of logstash config:
51
+ #
52
+ # [source,json]
53
+ # --------------------------
54
+ # output {
55
+ # google_cloud_storage {
56
+ # bucket => "my_bucket" (required)
57
+ # json_key_file => "/path/to/privatekey.json" (optional)
58
+ # temp_directory => "/tmp/logstash-gcs" (optional)
59
+ # log_file_prefix => "logstash_gcs" (optional)
60
+ # max_file_size_kbytes => 1024 (optional)
61
+ # output_format => "plain" (optional)
62
+ # date_pattern => "%Y-%m-%dT%H:00" (optional)
63
+ # flush_interval_secs => 2 (optional)
64
+ # gzip => false (optional)
65
+ # gzip_content_encoding => false (optional)
66
+ # uploader_interval_secs => 60 (optional)
67
+ # upload_synchronous => false (optional)
68
+ # }
69
+ # }
70
+ # --------------------------
71
+ #
72
+ # Improvements TODO list:
73
+ # * Support logstash event variables to determine filename.
74
+ # * Turn Google API code into a Plugin Mixin (like AwsConfig).
75
+ # * There's no recover method, so if logstash/plugin crashes, files may not
76
+ # be uploaded to GCS.
77
+ # * Allow user to configure file name.
78
+ class LogStash::Outputs::GoogleCloudStorage < LogStash::Outputs::Base
79
+ config_name "google_cloud_storage"
80
+
81
+ concurrency :single
82
+
83
+ # GCS bucket name, without "gs://" or any other prefix.
84
+ config :bucket, :validate => :string, :required => true
85
+
86
+ # GCS path to private key file.
87
+ config :key_path, :validate => :string, :obsolete => 'Use json_key_file or ADC instead.'
88
+
89
+ # GCS private key password.
90
+ config :key_password, :validate => :string, :deprecated => 'Use json_key_file or ADC instead.'
91
+
92
+ # GCS service account.
93
+ config :service_account, :validate => :string, :deprecated => 'Use json_key_file or ADC instead.'
94
+
95
+ # Directory where temporary files are stored.
96
+ # Defaults to /tmp/logstash-gcs-<random-suffix>
97
+ config :temp_directory, :validate => :string, :default => ""
98
+
99
+ # Log file prefix. Log file will follow the format:
100
+ # <prefix>_hostname_date<.part?>.log
101
+ config :log_file_prefix, :validate => :string, :default => "logstash_gcs"
102
+
103
+ # Sets max file size in kbytes. 0 disable max file check.
104
+ config :max_file_size_kbytes, :validate => :number, :default => 10000
105
+
106
+ # The event format you want to store in files. Defaults to plain text.
107
+ config :output_format, :validate => [ "json", "plain" ], :default => "plain"
108
+
109
+ # Time pattern for log file, defaults to hourly files.
110
+ # Must Time.strftime patterns: www.ruby-doc.org/core-2.0/Time.html#method-i-strftime
111
+ config :date_pattern, :validate => :string, :default => "%Y-%m-%dT%H:00"
112
+
113
+ # Flush interval in seconds for flushing writes to log files. 0 will flush
114
+ # on every message.
115
+ config :flush_interval_secs, :validate => :number, :default => 2
116
+
117
+ # Gzip output stream when writing events to log files, set
118
+ # `Content-Type` to `application/gzip` instead of `text/plain`, and
119
+ # use file suffix `.log.gz` instead of `.log`.
120
+ config :gzip, :validate => :boolean, :default => false
121
+
122
+ # Gzip output stream when writing events to log files and set
123
+ # `Content-Encoding` to `gzip`.
124
+ config :gzip_content_encoding, :validate => :boolean, :default => false
125
+
126
+ # Uploader interval when uploading new files to GCS. Adjust time based
127
+ # on your time pattern (for example, for hourly files, this interval can be
128
+ # around one hour).
129
+ config :uploader_interval_secs, :validate => :number, :default => 60
130
+
131
+ # Should the hostname be included in the file name?
132
+ config :include_hostname, :validate => :boolean, :default => true
133
+
134
+ # Should a UUID be included in the file name?
135
+ config :include_uuid, :validate => :boolean, :default => false
136
+
137
+ # The path to the service account's JSON credentials file.
138
+ # Application Default Credentials (ADC) are used if the path is blank.
139
+ # See: https://cloud.google.com/docs/authentication/production
140
+ #
141
+ # You must run on GCP for ADC to work.
142
+ config :json_key_file, :validate => :string, :default => ""
143
+
144
+ # When true, files are uploaded by the event processing thread as soon as a file is ready.
145
+ # When false, (the default behaviour), files will be uploaded in a dedicated thread.
146
+ #
147
+ # Enabling this option provides greater likelihood that all generated files will be
148
+ # to GCS, especially in the event of a graceful shutdown of logstash, such as when an
149
+ # input plugin reaches the end of events. This comes at the price of introducing delays
150
+ # in the event processing pipeline as files are uploaded.
151
+ #
152
+ # When this feature is enabled, the uploader_interval_secs option has no effect.
153
+ config :upload_synchronous, :validate => :boolean, :default => false
154
+
155
+ config :max_concurrent_uploads, :validate => :number, :default => 5
156
+
157
+ public
158
+ def register
159
+ @logger.debug('Registering Google Cloud Storage plugin')
160
+
161
+ @workers = LogStash::Outputs::Gcs::WorkerPool.new(@max_concurrent_uploads, @upload_synchronous)
162
+ initialize_temp_directory
163
+ initialize_path_factory
164
+ initialize_log_rotater
165
+
166
+ initialize_google_client
167
+
168
+ start_uploader
169
+
170
+ @content_type = @gzip ? 'application/gzip' : 'text/plain'
171
+ @content_encoding = @gzip_content_encoding ? 'gzip' : 'identity'
172
+ end
173
+
174
+ # Method called for each log event. It writes the event to the current output
175
+ # file, flushing depending on flush interval configuration.
176
+ public
177
+ def receive(event)
178
+ @logger.debug('Received event', :event => event)
179
+
180
+ if @output_format == 'json'
181
+ message = LogStash::Json.dump(event.to_hash)
182
+ else
183
+ message = event.to_s
184
+ end
185
+
186
+ @log_rotater.writeln(message)
187
+ end
188
+
189
+ public
190
+ def close
191
+ @logger.debug('Stopping the plugin, uploading the remaining files.')
192
+ Stud.stop!(@registration_thread) unless @registration_thread.nil?
193
+
194
+ # Force rotate the log. If it contains data it will be submitted
195
+ # to the work pool and will be uploaded before the plugin stops.
196
+ @log_rotater.rotate_log!
197
+ @workers.stop!
198
+ end
199
+
200
+ private
201
+
202
+ ##
203
+ # Creates temporary directory, if it does not exist.
204
+ #
205
+ # A random suffix is appended to the temporary directory
206
+ def initialize_temp_directory
207
+ require "stud/temporary"
208
+
209
+ if @temp_directory.empty?
210
+ @temp_directory = Stud::Temporary.directory('logstash-gcs')
211
+ end
212
+
213
+ FileUtils.mkdir_p(@temp_directory) unless File.directory?(@temp_directory)
214
+
215
+ @logger.info("Using temporary directory: #{@temp_directory}")
216
+ end
217
+
218
+ def initialize_path_factory
219
+ @path_factory = LogStash::Outputs::Gcs::PathFactoryBuilder.build do |builder|
220
+ builder.set_directory(@temp_directory)
221
+ builder.set_prefix(@log_file_prefix)
222
+ builder.set_include_host(@include_hostname)
223
+ builder.set_date_pattern(@date_pattern)
224
+ builder.set_include_part(@max_file_size_kbytes > 0)
225
+ builder.set_include_uuid(@include_uuid)
226
+ builder.set_is_gzipped(@gzip)
227
+ end
228
+ end
229
+
230
+ # start_uploader periodically sends flush events through the log rotater
231
+ def start_uploader
232
+ @registration_thread = Thread.new do
233
+ Stud.interval(@uploader_interval_secs) do
234
+ @log_rotater.writeln(nil)
235
+ end
236
+ end
237
+ end
238
+
239
+ ##
240
+ # Initializes Google Client instantiating client and authorizing access.
241
+ def initialize_google_client
242
+ @client = LogStash::Outputs::Gcs::Client.new(@bucket, @json_key_file, @logger)
243
+ end
244
+
245
+ ##
246
+ # Uploads a local file to the configured bucket.
247
+ def upload_object(filename)
248
+ @client.upload_object(filename, @content_encoding, @content_type)
249
+ end
250
+
251
+ def upload_and_delete(filename)
252
+ file_size = File.stat(filename).size
253
+
254
+ if file_size > 0
255
+ upload_object(filename)
256
+ else
257
+ @logger.debug('File size is zero, skip upload.', :filename => filename)
258
+ end
259
+
260
+ @logger.debug('Delete local temporary file', :filename => filename)
261
+ File.delete(filename)
262
+ end
263
+
264
+ def initialize_log_rotater
265
+ max_file_size = @max_file_size_kbytes * 1024
266
+ @log_rotater = LogStash::Outputs::Gcs::LogRotate.new(@path_factory, max_file_size, @gzip, @flush_interval_secs, @gzip_content_encoding)
267
+
268
+ @log_rotater.on_rotate do |filename|
269
+ @logger.info("Rotated out file: #{filename}")
270
+ @workers.post do
271
+ upload_and_delete(filename)
272
+ end
273
+ end
274
+ end
275
+ attr_accessor :active
276
+ end
@@ -0,0 +1,33 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'logstash-output-google_cloud_storage'
3
+ s.version = '4.0.0'
4
+ s.licenses = ['Apache-2.0']
5
+ s.summary = "plugin to upload log events to Google Cloud Storage (GCS)"
6
+ s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
7
+ s.authors = ["Elastic"]
8
+ s.email = 'info@elastic.co'
9
+ s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
10
+ s.require_paths = ["lib", "vendor/jar-dependencies"]
11
+
12
+ # Files
13
+ s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
14
+
15
+ # Tests
16
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
+
18
+ # Special flag to let us know this is actually a logstash plugin
19
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
20
+
21
+ # Gem dependencies
22
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
23
+
24
+ s.add_runtime_dependency 'stud'
25
+ s.add_runtime_dependency 'logstash-codec-plain'
26
+ s.add_runtime_dependency 'mime-types', '~> 2' # last version compatible with ruby 2.x
27
+ s.add_runtime_dependency 'concurrent-ruby' # use version bundled with Logstash to avoid platform mismatch on plugin install
28
+ s.add_development_dependency 'logstash-devutils'
29
+
30
+ # JARs
31
+ s.platform = 'java'
32
+ end
33
+
@@ -0,0 +1,8 @@
1
+ {
2
+ "//": "Dummy account from https://github.com/GoogleCloudPlatform/google-cloud-java/google-cloud-clients/google-cloud-core/src/test/java/com/google/cloud/ServiceOptionsTest.java",
3
+ "private_key_id": "somekeyid",
4
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+K2hSuFpAdrJI\nnCgcDz2M7t7bjdlsadsasad+fvRSW6TjNQZ3p5LLQY1kSZRqBqylRkzteMOyHgaR\n0Pmxh3ILCND5men43j3h4eDbrhQBuxfEMalkG92sL+PNQSETY2tnvXryOvmBRwa/\nQP/9dJfIkIDJ9Fw9N4Bhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\nknddadwkwewcVxHFhcZJO+XWf6ofLUXpRwiTZakGMn8EE1uVa2LgczOjwWHGi99MFjxSer5m9\n1tCa3/KEGKiS/YL71JvjwX3mb+cewlkcmweBKZHM2JPTk0ZednFSpVZMtycjkbLa\ndYOS8V85AgMBewECggEBAKksaldajfDZDV6nGqbFjMiizAKJolr/M3OQw16K6o3/\n0S31xIe3sSlgW0+UbYlF4U8KifhManD1apVSC3csafaspP4RZUHFhtBywLO9pR5c\nr6S5aLp+gPWFyIp1pfXbWGvc5VY/v9x7ya1VEa6rXvLsKupSeWAW4tMj3eo/64ge\nsdaceaLYw52KeBYiT6+vpsnYrEkAHO1fF/LavbLLOFJmFTMxmsNaG0tuiJHgjshB\n82DpMCbXG9YcCgI/DbzuIjsdj2JC1cascSP//3PmefWysucBQe7Jryb6NQtASmnv\nCdDw/0jmZTEjpe4S1lxfHplAhHFtdgYTvyYtaLZiVVkCgYEA8eVpof2rceecw/I6\n5ng1q3Hl2usdWV/4mZMvR0fOemacLLfocX6IYxT1zA1FFJlbXSRsJMf/Qq39mOR2\nSpW+hr4jCoHeRVYLgsbggtrevGmILAlNoqCMpGZ6vDmJpq6ECV9olliDvpPgWOP+\nmYPDreFBGxWvQrADNbRt2dmGsrsCgYEAyUHqB2wvJHFqdmeBsaacewzV8x9WgmeX\ngUIi9REwXlGDW0Mz50dxpxcKCAYn65+7TCnY5O/jmL0VRxU1J2mSWyWTo1C+17L0\n3fUqjxL1pkefwecxwecvC+gFFYdJ4CQ/MHHXU81Lwl1iWdFCd2UoGddYaOF+KNeM\nHC7cmqra+JsCgYEAlUNywzq8nUg7282E+uICfCB0LfwejuymR93CtsFgb7cRd6ak\nECR8FGfCpH8ruWJINllbQfcHVCX47ndLZwqv3oVFKh6pAS/vVI4dpOepP8++7y1u\ncoOvtreXCX6XqfrWDtKIvv0vjlHBhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\nkndj5uNl5SiuVxHFhcZJO+XWf6ofLUregtevZakGMn8EE1uVa2AY7eafmoU/nZPT\n00YB0TBATdCbn/nBSuKDESkhSg9s2GEKQZG5hBmL5uCMfo09z3SfxZIhJdlerreP\nJ7gSidI12N+EZxYd4xIJh/HFDgp7RRO87f+WJkofMQKBgGTnClK1VMaCRbJZPriw\nEfeFCoOX75MxKwXs6xgrw4W//AYGGUjDt83lD6AZP6tws7gJ2IwY/qP7+lyhjEqN\nHtfPZRGFkGZsdaksdlaksd323423d+15/UvrlRSFPNj1tWQmNKkXyRDW4IG1Oa2p\nrALStNBx5Y9t0/LQnFI4w3aG\n-----END PRIVATE KEY-----\n",
5
+ "client_email": "someclientid@developer.gserviceaccount.com",
6
+ "client_id": "someclientid.apps.googleusercontent.com",
7
+ "type": "service_account"
8
+ }
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ require 'logstash/outputs/gcs/client'
4
+
5
+ describe LogStash::Outputs::Gcs::Client do
6
+
7
+ # This test is mostly to make sure the Java types, signatures and classes
8
+ # haven't changed being that JRuby is very relaxed.
9
+ describe '#initialize' do
10
+ let(:logger) { spy('logger') }
11
+
12
+ it 'does not throw an error when initializing' do
13
+ key_file = ::File.join('spec', 'fixtures', 'credentials.json')
14
+ key_file = ::File.absolute_path(key_file)
15
+ LogStash::Outputs::Gcs::Client.new('my-bucket', key_file, logger)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,129 @@
1
+ # encoding: utf-8
2
+ require 'logstash/outputs/gcs/log_rotate'
3
+ require 'logstash/outputs/gcs/path_factory'
4
+ require 'logstash/outputs/gcs/temp_log_file'
5
+
6
+ describe LogStash::Outputs::Gcs::LogRotate do
7
+ let(:tempdir){ Stud::Temporary.directory }
8
+ let(:path_factory) do
9
+ LogStash::Outputs::Gcs::PathFactoryBuilder.build do |builder|
10
+ builder.set_directory tempdir
11
+ builder.set_prefix 'prefix'
12
+ builder.set_include_host true
13
+ builder.set_date_pattern ''
14
+ builder.set_include_part true
15
+ builder.set_include_uuid true
16
+ builder.set_is_gzipped true
17
+ end
18
+ end
19
+ let(:open_file_1) { double('open-temp-1', :size => 5, :path => 'one', :close! => true, :time_since_sync => 10, :fsync => true)}
20
+ let(:open_file_2) { double('open-temp-2', :size => 5, :path => 'two', :close! => true, :time_since_sync => 60, :fsync => true)}
21
+
22
+ describe '#initialize' do
23
+ it 'opens the first file' do
24
+ expect(LogStash::Outputs::Gcs::LogFileFactory).to receive(:create).and_return(open_file_1)
25
+
26
+ LogStash::Outputs::Gcs::LogRotate.new(path_factory, 10, false, 30)
27
+ end
28
+ end
29
+
30
+ describe '#writeln' do
31
+ subject { LogStash::Outputs::Gcs::LogRotate.new(path_factory, 10, false, 30) }
32
+
33
+ it 'does not rotate if size is small and path is the same' do
34
+ expect(path_factory).to receive(:should_rotate?).and_return(false)
35
+ # once for init
36
+ expect(path_factory).to receive(:rotate_path!).once
37
+
38
+ subject.writeln('foo')
39
+ end
40
+
41
+ it 'rotates the file if the size is too big' do
42
+ # once for init, once for writeln
43
+ expect(path_factory).to receive(:rotate_path!).twice
44
+
45
+ subject.writeln('this line is longer than ten characters' * 1000)
46
+ subject.writeln('flush')
47
+ end
48
+
49
+ it 'rotates the file if the path changed' do
50
+ expect(path_factory).to receive(:should_rotate?).and_return(true)
51
+ # once for init, once for writeln
52
+ expect(path_factory).to receive(:rotate_path!).twice
53
+
54
+ subject.writeln('foo')
55
+ end
56
+
57
+ it 'writes the message' do
58
+ expect(LogStash::Outputs::Gcs::LogFileFactory).to receive(:create).and_return(open_file_1)
59
+ expect(open_file_1).to receive(:write).with('foo', "\n")
60
+
61
+ subject.writeln('foo')
62
+ end
63
+
64
+ it 'does not write nil messages' do
65
+ expect(LogStash::Outputs::Gcs::LogFileFactory).to receive(:create).and_return(open_file_1)
66
+ expect(open_file_1).not_to receive(:write)
67
+
68
+ subject.writeln(nil)
69
+ end
70
+
71
+ it 'does not fsync if delta less than limit' do
72
+ expect(LogStash::Outputs::Gcs::LogFileFactory).to receive(:create).and_return(open_file_1)
73
+ expect(open_file_1).not_to receive(:fsync)
74
+
75
+ subject.writeln(nil)
76
+ end
77
+
78
+ it 'fsyncs if delta greater than limit' do
79
+ expect(LogStash::Outputs::Gcs::LogFileFactory).to receive(:create).and_return(open_file_2)
80
+ expect(open_file_2).to receive(:fsync)
81
+
82
+ subject.writeln(nil)
83
+ end
84
+ end
85
+
86
+ describe '#rotate_log!' do
87
+ subject { LogStash::Outputs::Gcs::LogRotate.new(path_factory, 10, false, 30) }
88
+
89
+ before :each do
90
+ allow(LogStash::Outputs::Gcs::LogFileFactory).to receive(:create).and_return(open_file_1, open_file_2)
91
+ end
92
+
93
+ it 'closes the old file' do
94
+ expect(open_file_1).to receive(:close!)
95
+
96
+ subject.rotate_log!
97
+ end
98
+
99
+ it 'calls the callback with the old file name' do
100
+ value = nil
101
+ subject.on_rotate { |old_path| value = old_path }
102
+
103
+ subject.rotate_log!
104
+ expect(value).to eq(open_file_1.path)
105
+ end
106
+
107
+ it 'opens a new file based on the new path' do
108
+ expect(LogStash::Outputs::Gcs::LogFileFactory).to receive(:create).and_return(open_file_1, open_file_2)
109
+ expect(open_file_2).to receive(:write).with('foo', "\n")
110
+
111
+ subject.rotate_log!
112
+ subject.writeln('foo')
113
+ end
114
+ end
115
+
116
+ describe '#on_rotate' do
117
+ subject { LogStash::Outputs::Gcs::LogRotate.new(path_factory, 10, false, 30) }
118
+
119
+ it 'replaces an existing callback' do
120
+ value = :none
121
+
122
+ subject.on_rotate { value = :first }
123
+ subject.on_rotate { value = :second }
124
+
125
+ subject.rotate_log!
126
+ expect(value).to eq(:second)
127
+ end
128
+ end
129
+ end