Class: Fluent::BigQueryOutput
- Inherits:
-
BufferedOutput
- Object
- BufferedOutput
- Fluent::BigQueryOutput
show all
- Defined in:
- lib/fluent/plugin/out_bigquery.rb
Overview
TODO: error classes for each api error responses
class BigQueryAPIError < StandardError
end
Defined Under Namespace
Classes: BooleanFieldSchema, FieldSchema, FloatFieldSchema, IntegerFieldSchema, RecordSchema, StringFieldSchema
Instance Method Summary
collapse
Constructor Details
Table types
https://developers.google.com/bigquery/docs/tables
type - The following data types are supported; see Data Formats for details on each data type:
STRING
INTEGER
FLOAT
BOOLEAN
RECORD A JSON object, used when importing nested records. This type is only available when using JSON source files.
mode - Whether a field can be null. The following values are supported:
NULLABLE - The cell can be null.
REQUIRED - The cell cannot be null.
REPEATED - Zero or more repeated simple or nested subfields. This mode is only supported when using JSON source files.
118
119
120
121
122
123
124
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 118
def initialize
super
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'google/api_client/auth/compute_service_account'
end
|
Instance Method Details
#client ⇒ Object
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 192
def client
return @cached_client if @cached_client && @cached_client_expiration > Time.now
client = Google::APIClient.new(
:application_name => 'Fluentd BigQuery plugin',
:application_version => Fluent::BigQueryPlugin::VERSION
)
case @auth_method
when 'private_key'
key = Google::APIClient::PKCS12.load_key( @private_key_path, @private_key_passphrase )
asserter = Google::APIClient::JWTAsserter.new(
@email,
"https://www.googleapis.com/auth/bigquery",
key
)
client.authorization = asserter.authorize
when 'compute_engine'
auth = Google::APIClient::ComputeServiceAccount.new
auth.fetch_access_token!
client.authorization = auth
else
raise ConfigError, "Unknown auth method: #{@auth_method}"
end
@cached_client_expiration = Time.now + 1800
@cached_client = client
end
|
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 126
def configure(conf)
super
case @auth_method
when 'private_key'
if !@email || !@private_key_path
raise Fluent::ConfigError, "'email' and 'private_key_path' must be specified if auth_method == 'private_key'"
end
when 'compute_engine'
else
raise Fluent::ConfigError, "unrecognized 'auth_method': #{@auth_method}"
end
if (!@table && !@tables) || (@table && @table)
raise Fluent::ConfigError, "'table' or 'tables' must be specified, and both are invalid"
end
@tablelist = @tables ? @tables.split(',') : [@table]
@fields = RecordSchema.new
if @field_string
@field_string.split(',').each do |fieldname|
@fields.register_field fieldname, :string
end
end
if @field_integer
@field_integer.split(',').each do |fieldname|
@fields.register_field fieldname, :integer
end
end
if @field_float
@field_float.split(',').each do |fieldname|
@fields.register_field fieldname, :float
end
end
if @field_boolean
@field_boolean.split(',').each do |fieldname|
@fields.register_field fieldname, :boolean
end
end
if @localtime.nil?
if @utc
@localtime = false
end
end
@timef = TimeFormatter.new(@time_format, @localtime)
end
|
259
260
261
262
263
264
265
266
267
268
269
270
271
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 259
def format_stream(tag, es)
super
buf = ''
es.each do |time, record|
row = if @time_field
@fields.format(record.merge({@time_field => @timef.format(time)}))
else
@fields.format(record)
end
buf << {"json" => row}.to_msgpack unless row.empty?
end
buf
end
|
#insert(table_id, rows) ⇒ Object
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 224
def insert(table_id, rows)
res = client().execute(
:api_method => @bq.tabledata.insert_all,
:parameters => {
'projectId' => @project,
'datasetId' => @dataset,
'tableId' => table_id,
},
:body_object => {
"rows" => rows
}
)
unless res.success?
@cached_client = nil
message = res.body
if res.body =~ /^\{/
begin
res_obj = JSON.parse(res.body)
message = res_obj['error']['message'] || res.body
rescue => e
$log.warn "Parse error: google api error response body", :body => res.body
end
end
$log.error "tabledata.insertAll API", :project_id => @project_id, :dataset => @dataset_id, :table => table_id, :code => res.status, :message => message
raise "failed to insert into bigquery" end
end
|
#load ⇒ Object
254
255
256
257
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 254
def load
raise NotImplementedError end
|
#shutdown ⇒ Object
187
188
189
190
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 187
def shutdown
super
end
|
#start ⇒ Object
176
177
178
179
180
181
182
183
184
185
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 176
def start
super
@bq = client.discovered_api("bigquery", "v2") @cached_client = nil
@cached_client_expiration = nil
@tables_queue = @tablelist.dup.shuffle
@tables_mutex = Mutex.new
end
|
#write(chunk) ⇒ Object
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
|
# File 'lib/fluent/plugin/out_bigquery.rb', line 273
def write(chunk)
rows = []
chunk.msgpack_each do |row_object|
rows << row_object
end
insert_table = @tables_mutex.synchronize do
t = @tables_queue.shift
@tables_queue.push t
t
end
insert(insert_table, rows)
end
|