logstash-output-google_bigquery 4.0.1-java → 4.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c388bf700fa17c45b9dcf608fba0515280154734c8eac3b9c92eb6d3d8d31446
4
- data.tar.gz: ab5fccb22f53cabd993d333b8c49bbdf3e2dccf5c6e6b27f00fea4a247b339e3
3
+ metadata.gz: 31a414a63c70fc7b35c690e076db1d1595785c79187a94e361b50d8632161496
4
+ data.tar.gz: 70622ec5c509cd8ac319e4e021b04086a841952b51619dd99fdaa4e2ac21c0a6
5
5
  SHA512:
6
- metadata.gz: 8223e186bd7ebc7300317bf1fafb24351057a90c0edead491025763f63f14dd3b2218185bb1ff70c8656dbbfad3085ee499812f275d2f14e05cd8760f9a48915
7
- data.tar.gz: 635eddd9885c24236600072cd648ba86e9ee69a2366a625b8068fffe142e301be1056f05b74bf9799ccc86da34f190cfac093e773068bc4a1d56ce6aab5da2c1
6
+ metadata.gz: b0157e8e33e82c5532bf13cb758ef74d55b05c5ee32185ba53ae0f3dfefbfbc34bcd0df8eac2d1c024b01be93c034ad923e15741df31cb37a84746e944ffe69f
7
+ data.tar.gz: 31a7c30f4a4bd0d5b95cfec1f4e569961263527a81f8d92b97c0d9ec04dcff8b73c4f5fe4c118cc307543a12958d0986a33ea35e9e45f3c89e7363dcf8a501d5
@@ -1,3 +1,8 @@
1
+ ## 4.1.0
2
+ - Added `skip_invalid_rows` configuration which will insert all valid rows of a BigQuery insert
3
+ and skip any invalid ones.
4
+ - Fixes [#5](https://github.com/logstash-plugins/logstash-output-google_bigquery/issues/5)
5
+
1
6
  ## 4.0.1
2
7
  - Documentation cleanup
3
8
 
@@ -99,6 +99,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
99
99
  | <<plugins-{type}s-{plugin}-key_path>> |<<string,string>>|*Obsolete*
100
100
  | <<plugins-{type}s-{plugin}-project_id>> |<<string,string>>|Yes
101
101
  | <<plugins-{type}s-{plugin}-service_account>> |<<string,string>>|__Deprecated__
102
+ | <<plugins-{type}s-{plugin}-skip_invalid_rows>> |<<boolean,boolean>>|No
102
103
  | <<plugins-{type}s-{plugin}-table_prefix>> |<<string,string>>|No
103
104
  | <<plugins-{type}s-{plugin}-table_separator>> |<<string,string>>|No
104
105
  | <<plugins-{type}s-{plugin}-temp_directory>> |<<string,string>>|__Deprecated__
@@ -174,6 +175,9 @@ added[4.0.0]
174
175
  * Default value is `"/tmp/bigquery"`.
175
176
 
176
177
  The location to store events that could not be uploaded due to errors.
178
+ By default if _any_ message in an insert is invalid all will fail.
179
+ You can use <<plugins-{type}s-{plugin}-skip_invalid_rows>> to allow partial inserts.
180
+
177
181
  Consider using an additional Logstash input to pipe the contents of
178
182
  these to an alert platform so you can manually fix the events.
179
183
 
@@ -298,6 +302,17 @@ deprecated[4.0.0, Replaced by `json_key_file` or by using ADC. See <<plugins-{ty
298
302
 
299
303
  * Value type is <<string,string>>
300
304
 
305
+ [id="plugins-{type}s-{plugin}-skip_invalid_rows"]
306
+ ===== `skip_invalid_rows`
307
+
308
+ added[4.1.0]
309
+
310
+ * Value type is <<boolean,boolean>>
311
+ * Default value is `false`
312
+
313
+ Insert all valid rows of a request, even if invalid rows exist.
314
+ The default value is false, which causes the entire request to fail if any invalid rows exist.
315
+
301
316
  [id="plugins-{type}s-{plugin}-table_prefix"]
302
317
  ===== `table_prefix`
303
318
 
@@ -36,18 +36,20 @@ module LogStash
36
36
  @bigquery.create table_info
37
37
  end
38
38
 
39
- def append(dataset, table, rows, ignore_unknown)
39
+ def append(dataset, table, rows, ignore_unknown, skip_invalid)
40
40
  api_debug("Appending #{rows.length} rows", dataset, table)
41
41
 
42
- request = build_append_request dataset, table, rows, ignore_unknown
42
+ request = build_append_request(dataset, table, rows, ignore_unknown, skip_invalid)
43
43
 
44
44
  response = @bigquery.insertAll request
45
- return true unless response.hasErrors
45
+ return [] unless response.hasErrors
46
46
 
47
+ failed_rows = []
47
48
  response.getInsertErrors().entrySet().each{ |entry|
48
49
  key = entry.getKey
49
- errors = entry.getValue
50
+ failed_rows << rows[key]
50
51
 
52
+ errors = entry.getValue
51
53
  errors.each{|bqError|
52
54
  @logger.warn('Error while inserting',
53
55
  key: key,
@@ -57,12 +59,13 @@ module LogStash
57
59
  }
58
60
  }
59
61
 
60
- false
62
+ failed_rows
61
63
  end
62
64
 
63
- def build_append_request(dataset, table, rows, ignore_unknown)
65
+ def build_append_request(dataset, table, rows, ignore_unknown, skip_invalid)
64
66
  request = com.google.cloud.bigquery.InsertAllRequest.newBuilder dataset, table
65
67
  request.setIgnoreUnknownValues ignore_unknown
68
+ request.setSkipInvalidRows(skip_invalid)
66
69
 
67
70
  rows.each { |serialized_row|
68
71
  # deserialize rows into Java maps
@@ -75,7 +78,7 @@ module LogStash
75
78
 
76
79
  # raises an exception if the key file is invalid
77
80
  def get_key_file_error(json_key_file)
78
- return nil if json_key_file.nil? || json_key_file == ''
81
+ return nil if nil_or_empty?(json_key_file)
79
82
 
80
83
  abs = ::File.absolute_path json_key_file
81
84
  unless abs == json_key_file
@@ -94,16 +97,10 @@ module LogStash
94
97
  err = get_key_file_error json_key_file
95
98
  raise err unless err.nil?
96
99
 
97
- if json_key_file.nil? || json_key_file.empty?
98
- return com.google.cloud.bigquery.BigQueryOptions.getDefaultInstance().getService()
99
- end
100
-
101
- # TODO: set User-Agent
102
-
103
- key_file = java.io.FileInputStream.new json_key_file
104
- credentials = com.google.auth.oauth2.ServiceAccountCredentials.fromStream key_file
105
- return com.google.cloud.bigquery.BigQueryOptions.newBuilder()
106
- .setCredentials(credentials)
100
+ com.google.cloud.bigquery.BigQueryOptions.newBuilder()
101
+ .setCredentials(credentials(json_key_file))
102
+ .setHeaderProvider(http_headers)
103
+ .setRetrySettings(retry_settings)
107
104
  .setProjectId(project_id)
108
105
  .build()
109
106
  .getService()
@@ -111,9 +108,45 @@ module LogStash
111
108
 
112
109
  private
113
110
 
111
+ java_import 'com.google.auth.oauth2.GoogleCredentials'
112
+ def credentials(json_key_path)
113
+ return GoogleCredentials.getApplicationDefault() if nil_or_empty?(json_key_path)
114
+
115
+ key_file = java.io.FileInputStream.new(json_key_path)
116
+ GoogleCredentials.fromStream(key_file)
117
+ end
118
+
119
+ java_import 'com.google.api.gax.rpc.FixedHeaderProvider'
120
+ def http_headers
121
+ gem_name = 'logstash-output-google_bigquery'
122
+ gem_version = '4.1.0'
123
+ user_agent = "Elastic/#{gem_name} version/#{gem_version}"
124
+
125
+ FixedHeaderProvider.create({ 'User-Agent' => user_agent })
126
+ end
127
+
128
+ java_import 'com.google.api.gax.retrying.RetrySettings'
129
+ java_import 'org.threeten.bp.Duration'
130
+ def retry_settings
131
+ # backoff values taken from com.google.api.client.util.ExponentialBackOff
132
+ RetrySettings.newBuilder()
133
+ .setInitialRetryDelay(Duration.ofMillis(500))
134
+ .setRetryDelayMultiplier(1.5)
135
+ .setMaxRetryDelay(Duration.ofSeconds(60))
136
+ .setInitialRpcTimeout(Duration.ofSeconds(20))
137
+ .setRpcTimeoutMultiplier(1.5)
138
+ .setMaxRpcTimeout(Duration.ofSeconds(20))
139
+ .setTotalTimeout(Duration.ofMinutes(15))
140
+ .build()
141
+ end
142
+
114
143
  def api_debug(message, dataset, table)
115
144
  @logger.debug(message, dataset: dataset, table: table)
116
145
  end
146
+
147
+ def nil_or_empty?(param)
148
+ param.nil? || param.empty?
149
+ end
117
150
  end
118
151
  end
119
152
  end
@@ -160,6 +160,10 @@ class LogStash::Outputs::GoogleBigQuery < LogStash::Outputs::Base
160
160
  # Files names follow the pattern `[table name]-[UNIX timestamp].log`
161
161
  config :error_directory, validate: :string, required: true, default: '/tmp/bigquery_errors'
162
162
 
163
+ # Insert all valid rows of a request, even if invalid rows exist. The default value is false,
164
+ # which causes the entire request to fail if any invalid rows exist.
165
+ config :skip_invalid_rows, validate: :boolean, default: false
166
+
163
167
  # The following configuration options still exist to alert users that are using them
164
168
  config :uploader_interval_secs, validate: :number, deprecated: 'No longer used.'
165
169
  config :deleter_interval_secs, validate: :number, deprecated: 'No longer used.'
@@ -232,8 +236,8 @@ class LogStash::Outputs::GoogleBigQuery < LogStash::Outputs::Base
232
236
 
233
237
  create_table_if_not_exists table
234
238
 
235
- successful = @bq_client.append @dataset, table, messages, @ignore_unknown_values
236
- write_to_errors_file(messages, table) unless successful
239
+ failed_rows = @bq_client.append(@dataset, table, messages, @ignore_unknown_values, @skip_invalid_rows)
240
+ write_to_errors_file(failed_rows, table) unless failed_rows.empty?
237
241
  rescue StandardError => e
238
242
  @logger.error 'Error uploading data.', :exception => e
239
243
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-google_bigquery'
3
- s.version = '4.0.1'
3
+ s.version = '4.1.0'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = "Writes events to Google BigQuery"
6
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"
@@ -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/bigquery/streamclient'
4
+
5
+ describe LogStash::Outputs::BigQuery::StreamingClient 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::BigQuery::StreamingClient.new(key_file, 'my-project', logger)
16
+ end
17
+ end
18
+ end
@@ -74,7 +74,7 @@ describe LogStash::Outputs::GoogleBigQuery do
74
74
 
75
75
  it 'creates a table if it does not exist' do
76
76
  allow(subject).to receive(:create_table_if_not_exists).and_return(nil)
77
- allow(bq_client).to receive(:append).and_return(true)
77
+ allow(bq_client).to receive(:append).and_return([])
78
78
  allow(subject).to receive(:write_to_errors_file).and_return(nil)
79
79
  expect(subject).to receive(:create_table_if_not_exists)
80
80
 
@@ -83,7 +83,7 @@ describe LogStash::Outputs::GoogleBigQuery do
83
83
 
84
84
  it 'writes rows to a file on failed insert' do
85
85
  allow(subject).to receive(:create_table_if_not_exists).and_return(nil)
86
- allow(bq_client).to receive(:append).and_return(false)
86
+ allow(bq_client).to receive(:append).and_return([0])
87
87
  allow(subject).to receive(:write_to_errors_file).and_return(nil)
88
88
  expect(subject).to receive(:write_to_errors_file)
89
89
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-google_bigquery
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
4
+ version: 4.1.0
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-03 00:00:00.000000000 Z
11
+ date: 2018-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -107,8 +107,10 @@ files:
107
107
  - lib/logstash/outputs/bigquery/streamclient.rb
108
108
  - lib/logstash/outputs/google_bigquery.rb
109
109
  - logstash-output-google_bigquery.gemspec
110
+ - spec/fixtures/credentials.json
110
111
  - spec/outputs/bigquery/batcher_spec.rb
111
112
  - spec/outputs/bigquery/schema_spec.rb
113
+ - spec/outputs/bigquery/streamclient_spec.rb
112
114
  - spec/outputs/google_bigquery_spec.rb
113
115
  - vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-core/2.1.3/jackson-core-2.1.3.jar
114
116
  - vendor/jar-dependencies/com/google/api-client/google-api-client/1.23.0/google-api-client-1.23.0.jar
@@ -173,6 +175,8 @@ signing_key:
173
175
  specification_version: 4
174
176
  summary: Writes events to Google BigQuery
175
177
  test_files:
178
+ - spec/fixtures/credentials.json
176
179
  - spec/outputs/bigquery/batcher_spec.rb
177
180
  - spec/outputs/bigquery/schema_spec.rb
181
+ - spec/outputs/bigquery/streamclient_spec.rb
178
182
  - spec/outputs/google_bigquery_spec.rb