github.com/google/cloudprober@v0.11.3/contrib/gcp/bigquery/bigquery.go (about) 1 // Copyright 2020 The Cloudprober Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 /* 16 Package bigquery connects to the GCP BigQuery API and computes metrics suitable 17 for blackbox-probing. 18 */ 19 package bigquery 20 21 import ( 22 "context" 23 "fmt" 24 25 "cloud.google.com/go/bigquery" 26 ) 27 28 // The QueryRunner interface encapsulates the BigQuery API. 29 // 30 // Query() runs the given query on BQ and returns the result and an error, if 31 // any. 32 type QueryRunner interface { 33 Query(context.Context, string) (string, error) 34 } 35 36 type bigqueryRunner struct { 37 client *bigquery.Client 38 } 39 40 // Query takes a string in BQL and executes it on BigQuery, returning the 41 // result. 42 func (r *bigqueryRunner) Query(ctx context.Context, query string) (string, error) { 43 q := r.client.Query(query) 44 45 it, err := q.Read(ctx) 46 if err != nil { 47 return "", err 48 } 49 var row []bigquery.Value 50 51 if err = it.Next(&row); err != nil { 52 return "", err 53 } 54 return fmt.Sprint(row[0]), nil 55 } 56 57 // NewRunner creates a new BQ QueryRunner associated with the given projectID. 58 func NewRunner(ctx context.Context, projectID string) (QueryRunner, error) { 59 client, err := bigquery.NewClient(ctx, projectID) 60 if err != nil { 61 return nil, err 62 } 63 return &bigqueryRunner{client}, nil 64 } 65 66 // Probe executes queries against BQ and returns the resulting metrics. 67 // If no table is specified, Probe will execute a dummy query against BQ (such 68 // as 'SELECT 1'). Otherwise, table should specify an existing table in the 69 // format 'dataset.table'. 70 // 71 // The service account cloudprober runs under should have sufficient permissions 72 // to read the table. 73 func Probe(ctx context.Context, r QueryRunner, table string) (string, error) { 74 75 var metrics, result string 76 var err error 77 78 if table == "" { 79 result, err = r.Query(ctx, "SELECT 1") 80 metrics = fmt.Sprintf("%s %s", "bigquery_connect", result) 81 } else { 82 result, err = r.Query(ctx, "SELECT COUNT(*) FROM "+table) 83 metrics = fmt.Sprintf("%s %s", "row_count", result) 84 } 85 86 if err != nil { 87 return "", err 88 } 89 return metrics, nil 90 }