diff --git a/java-bigquery/google-cloud-bigquery/pom.xml b/java-bigquery/google-cloud-bigquery/pom.xml index 1dea6a396db7..5d6243e638bc 100644 --- a/java-bigquery/google-cloud-bigquery/pom.xml +++ b/java-bigquery/google-cloud-bigquery/pom.xml @@ -216,6 +216,11 @@ opentelemetry-sdk-trace test + + io.opentelemetry + opentelemetry-sdk-testing + test + diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpc.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpc.java index 16737dc4b713..2928e59c7ca5 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpc.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpc.java @@ -71,7 +71,9 @@ import com.google.common.collect.Iterables; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Scope; import java.io.IOException; import java.math.BigInteger; import java.util.List; @@ -162,27 +164,18 @@ public Dataset getDatasetSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getDataset = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getDataset = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getDataset") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "DatasetService") - .setAttribute("bq.rpc.method", "GetDataset") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - - Dataset dataset = bqGetRequest.execute(); - if (getDataset != null) { - getDataset.setAttribute("bq.rpc.response.dataset.id", dataset.getId()); - getDataset.end(); - } - return dataset; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.getDataset", + "DatasetService", + "GetDataset", + options, + span -> { + Dataset dataset = bqGetRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.dataset.id", dataset.getId()); + } + return dataset; + }); } @Override @@ -212,33 +205,26 @@ public Tuple> listDatasetsSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span listDatasets = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - listDatasets = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.listDatasets") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "DatasetService") - .setAttribute("bq.rpc.method", "ListDatasets") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", datasetsListRequest.getPageToken()) - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - - DatasetList datasetsList = datasetsListRequest.execute(); - Iterable datasets = datasetsList.getDatasets(); - if (listDatasets != null) { - listDatasets.setAttribute("bq.rpc.next_page_token", datasetsList.getNextPageToken()); - listDatasets.end(); - } - return Tuple.of( - datasetsList.getNextPageToken(), - Iterables.transform( - datasets != null ? datasets : ImmutableList.of(), - LIST_TO_DATASET)); + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.listDatasets", + "DatasetService", + "ListDatasets", + options, + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", datasetsListRequest.getPageToken()); + } + DatasetList datasetsList = datasetsListRequest.execute(); + Iterable datasets = datasetsList.getDatasets(); + if (span != null) { + span.setAttribute("bq.rpc.next_page_token", datasetsList.getNextPageToken()); + } + return Tuple.of( + datasetsList.getNextPageToken(), + Iterables.transform( + datasets != null ? datasets : ImmutableList.of(), + LIST_TO_DATASET)); + }); } @Override @@ -267,26 +253,18 @@ public Dataset createSkipExceptionTranslation(Dataset dataset, Map op .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span createDataset = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - createDataset = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.createDataset") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "DatasetService") - .setAttribute("bq.rpc.method", "InsertDataset") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Dataset datasetResponse = bqCreateRequest.execute(); - if (createDataset != null) { - createDataset.setAttribute("bq.rpc.response.dataset.id", datasetResponse.getId()); - createDataset.end(); - } - return datasetResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.createDataset", + "DatasetService", + "InsertDataset", + options, + span -> { + Dataset datasetResponse = bqCreateRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.dataset.id", datasetResponse.getId()); + } + return datasetResponse; + }); } @Override @@ -316,26 +294,18 @@ public Table createSkipExceptionTranslation(Table table, Map options) .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span createTable = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - createTable = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.createTable") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableService") - .setAttribute("bq.rpc.method", "InsertTable") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Table tableResponse = bqCreateRequest.execute(); - if (createTable != null) { - createTable.setAttribute("bq.rpc.response.table.id", tableResponse.getId()); - createTable.end(); - } - return tableResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.createTable", + "TableService", + "InsertTable", + options, + span -> { + Table tableResponse = bqCreateRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.table.id", tableResponse.getId()); + } + return tableResponse; + }); } @Override @@ -363,27 +333,19 @@ public Routine createSkipExceptionTranslation(Routine routine, Map op .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span createRoutine = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - createRoutine = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.createRoutine") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "RoutineService") - .setAttribute("bq.rpc.method", "InsertRoutine") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Routine routineResponse = bqCreateRequest.execute(); - if (createRoutine != null) { - createRoutine.setAttribute( - "bq.rpc.response.routine.id", routineResponse.getRoutineReference().getRoutineId()); - createRoutine.end(); - } - return routineResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.createRoutine", + "RoutineService", + "InsertRoutine", + options, + span -> { + Routine routineResponse = bqCreateRequest.execute(); + if (span != null) { + span.setAttribute( + "bq.rpc.response.routine.id", routineResponse.getRoutineReference().getRoutineId()); + } + return routineResponse; + }); } @Override @@ -413,28 +375,20 @@ public Job createSkipExceptionTranslation(Job job, Map options) throw .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span createJob = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - createJob = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.createJob") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "InsertJob") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Job jobResponse = bqCreateRequest.execute(); - if (createJob != null) { - createJob.setAttribute("bq.rpc.response.job.id", jobResponse.getId()); - createJob.setAttribute( - "bq.rpc.response.job.status.state", jobResponse.getStatus().getState()); - createJob.end(); - } - return jobResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.createJob", + "JobService", + "InsertJob", + options, + span -> { + Job jobResponse = bqCreateRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.job.id", jobResponse.getId()); + span.setAttribute( + "bq.rpc.response.job.status.state", jobResponse.getStatus().getState()); + } + return jobResponse; + }); } @Override @@ -460,27 +414,20 @@ public Job createJobForQuerySkipExceptionTranslation(Job job) throws IOException .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span createJob = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - createJob = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.createJobForQuery") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "InsertJob") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - Job jobResponse = bqCreateRequest.execute(); - if (createJob != null) { - createJob.setAttribute("bq.rpc.response.job.id", jobResponse.getId()); - createJob.setAttribute( - "bq.rpc.response.job.status.state", jobResponse.getStatus().getState()); - createJob.end(); - } - return jobResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.createJobForQuery", + "JobService", + "InsertJob", + null, + span -> { + Job jobResponse = bqCreateRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.job.id", jobResponse.getId()); + span.setAttribute( + "bq.rpc.response.job.status.state", jobResponse.getStatus().getState()); + } + return jobResponse; + }); } @Override @@ -511,25 +458,15 @@ public boolean deleteDatasetSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span deleteDataset = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - deleteDataset = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.deleteDataset") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "DatasetService") - .setAttribute("bq.rpc.method", "DeleteDataset") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - bqDeleteRequest.execute(); - if (deleteDataset != null) { - deleteDataset.end(); - } - return true; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.deleteDataset", + "DatasetService", + "DeleteDataset", + options, + span -> { + bqDeleteRequest.execute(); + return true; + }); } @Override @@ -562,26 +499,18 @@ public Dataset patchSkipExceptionTranslation(Dataset dataset, Map opt .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span patchDataset = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - patchDataset = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.patchDataset") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "DatasetService") - .setAttribute("bq.rpc.method", "PatchDataset") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Dataset datasetResponse = bqPatchRequest.execute(); - if (patchDataset != null) { - patchDataset.setAttribute("bq.rpc.response.dataset.id", datasetResponse.getId()); - patchDataset.end(); - } - return datasetResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.patchDataset", + "DatasetService", + "PatchDataset", + options, + span -> { + Dataset datasetResponse = bqPatchRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.dataset.id", datasetResponse.getId()); + } + return datasetResponse; + }); } @Override @@ -613,26 +542,18 @@ public Table patchSkipExceptionTranslation(Table table, Map options) .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span patchTable = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - patchTable = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.patchTable") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableService") - .setAttribute("bq.rpc.method", "PatchTable") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Table tableResponse = bqPatchRequest.execute(); - if (patchTable != null) { - patchTable.setAttribute("bq.rpc.response.table.id", tableResponse.getId()); - patchTable.end(); - } - return tableResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.patchTable", + "TableService", + "PatchTable", + options, + span -> { + Table tableResponse = bqPatchRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.table.id", tableResponse.getId()); + } + return tableResponse; + }); } @Override @@ -666,26 +587,18 @@ public Table getTableSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getTable = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getTable = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getTable") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableService") - .setAttribute("bq.rpc.method", "GetTable") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Table tableResponse = bqGetRequest.execute(); - if (getTable != null) { - getTable.setAttribute("bq.rpc.response.table.id", tableResponse.getId()); - getTable.end(); - } - return tableResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.getTable", + "TableService", + "GetTable", + options, + span -> { + Table tableResponse = bqGetRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.table.id", tableResponse.getId()); + } + return tableResponse; + }); } private String getTableMetadataOption(Map options) { @@ -721,48 +634,42 @@ public Tuple> listTablesSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span listTables = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - listTables = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.listTables") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableService") - .setAttribute("bq.rpc.method", "ListTables") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", tableListRequest.getPageToken()) - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - TableList tableResponse = tableListRequest.execute(); - if (listTables != null) { - listTables.setAttribute("bq.rpc.next_page_token", tableResponse.getNextPageToken()); - listTables.end(); - } - - Iterable tables = tableResponse.getTables(); - return Tuple.of( - tableResponse.getNextPageToken(), - Iterables.transform( - tables != null ? tables : ImmutableList.of(), - new Function() { - @Override - public Table apply(TableList.Tables tablePb) { - return new Table() - .setFriendlyName(tablePb.getFriendlyName()) - .setId(tablePb.getId()) - .setKind(tablePb.getKind()) - .setTableReference(tablePb.getTableReference()) - .setType(tablePb.getType()) - .setCreationTime(tablePb.getCreationTime()) - .setTimePartitioning(tablePb.getTimePartitioning()) - .setRangePartitioning(tablePb.getRangePartitioning()) - .setClustering(tablePb.getClustering()) - .setLabels(tablePb.getLabels()); - } - })); + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.listTables", + "TableService", + "ListTables", + options, + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", tableListRequest.getPageToken()); + } + TableList tableResponse = tableListRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.next_page_token", tableResponse.getNextPageToken()); + } + + Iterable tables = tableResponse.getTables(); + return Tuple.of( + tableResponse.getNextPageToken(), + Iterables.transform( + tables != null ? tables : ImmutableList.of(), + new Function() { + @Override + public Table apply(TableList.Tables tablePb) { + return new Table() + .setFriendlyName(tablePb.getFriendlyName()) + .setId(tablePb.getId()) + .setKind(tablePb.getKind()) + .setTableReference(tablePb.getTableReference()) + .setType(tablePb.getType()) + .setCreationTime(tablePb.getCreationTime()) + .setTimePartitioning(tablePb.getTimePartitioning()) + .setRangePartitioning(tablePb.getRangePartitioning()) + .setClustering(tablePb.getClustering()) + .setLabels(tablePb.getLabels()); + } + })); + }); } @Override @@ -789,24 +696,15 @@ public boolean deleteTableSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span deleteTable = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - deleteTable = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.deleteTable") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableService") - .setAttribute("bq.rpc.method", "DeleteTable") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - bqDeleteRequest.execute(); - if (deleteTable != null) { - deleteTable.end(); - } - return true; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.deleteTable", + "TableService", + "DeleteTable", + null, + span -> { + bqDeleteRequest.execute(); + return true; + }); } @Override @@ -836,27 +734,19 @@ public Model patchSkipExceptionTranslation(Model model, Map options) .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span patchModel = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - patchModel = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.patchModel") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "ModelService") - .setAttribute("bq.rpc.method", "PatchModel") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Model modelResponse = bqPatchRequest.execute(); - if (patchModel != null) { - patchModel.setAttribute( - "bq.rpc.response.model.id", modelResponse.getModelReference().getModelId()); - patchModel.end(); - } - return modelResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.patchModel", + "ModelService", + "PatchModel", + options, + span -> { + Model modelResponse = bqPatchRequest.execute(); + if (span != null) { + span.setAttribute( + "bq.rpc.response.model.id", modelResponse.getModelReference().getModelId()); + } + return modelResponse; + }); } @Override @@ -889,27 +779,19 @@ public Model getModelSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getModel = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getModel = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getModel") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "ModelService") - .setAttribute("bq.rpc.method", "GetModel") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Model modelResponse = bqGetRequest.execute(); - if (getModel != null) { - getModel.setAttribute( - "bq.rpc.response.model.id", modelResponse.getModelReference().getModelId()); - getModel.end(); - } - return modelResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.getModel", + "ModelService", + "GetModel", + options, + span -> { + Model modelResponse = bqGetRequest.execute(); + if (span != null) { + span.setAttribute( + "bq.rpc.response.model.id", modelResponse.getModelReference().getModelId()); + } + return modelResponse; + }); } @Override @@ -938,30 +820,26 @@ public Tuple> listModelsSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span listModels = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - listModels = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.listModels") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "ModelService") - .setAttribute("bq.rpc.method", "ListModels") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", modelListRequest.getPageToken()) - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - ListModelsResponse modelResponse = modelListRequest.execute(); - if (listModels != null) { - listModels.setAttribute("bq.rpc.next_page_token", modelResponse.getNextPageToken()); - listModels.end(); - } - - Iterable models = - modelResponse.getModels() != null ? modelResponse.getModels() : ImmutableList.of(); - return Tuple.of(modelResponse.getNextPageToken(), models); + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.listModels", + "ModelService", + "ListModels", + options, + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", modelListRequest.getPageToken()); + } + ListModelsResponse modelResponse = modelListRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.next_page_token", modelResponse.getNextPageToken()); + } + + Iterable models = + modelResponse.getModels() != null + ? modelResponse.getModels() + : ImmutableList.of(); + return Tuple.of(modelResponse.getNextPageToken(), models); + }); } @Override @@ -988,24 +866,14 @@ public boolean deleteModelSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span deleteModels = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - deleteModels = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.deleteModel") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "ModelService") - .setAttribute("bq.rpc.method", "DeleteModel") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - bqDeleteRequest.execute(); - if (deleteModels != null) { - deleteModels.end(); - } - return true; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.deleteModel", + "ModelService", + "DeleteModel", + span -> { + bqDeleteRequest.execute(); + return true; + }); } @Override @@ -1037,27 +905,19 @@ public Routine updateSkipExceptionTranslation(Routine routine, Map op .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span updateRoutine = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - updateRoutine = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.updateRoutine") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "RoutineService") - .setAttribute("bq.rpc.method", "UpdateRoutine") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Routine routineResponse = bqUpdateRequest.execute(); - if (updateRoutine != null) { - updateRoutine.setAttribute( - "bq.rpc.response.routine.id", routineResponse.getRoutineReference().getRoutineId()); - updateRoutine.end(); - } - return routineResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.updateRoutine", + "RoutineService", + "UpdateRoutine", + options, + span -> { + Routine routineResponse = bqUpdateRequest.execute(); + if (span != null) { + span.setAttribute( + "bq.rpc.response.routine.id", routineResponse.getRoutineReference().getRoutineId()); + } + return routineResponse; + }); } @Override @@ -1090,27 +950,19 @@ public Routine getRoutineSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getRoutine = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getRoutine = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getRoutine") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "RoutineService") - .setAttribute("bq.rpc.method", "GetRoutine") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Routine routineResponse = bqGetRequest.execute(); - if (getRoutine != null) { - getRoutine.setAttribute( - "bq.rpc.response.routine.id", routineResponse.getRoutineReference().getRoutineId()); - getRoutine.end(); - } - return routineResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.getRoutine", + "RoutineService", + "GetRoutine", + options, + span -> { + Routine routineResponse = bqGetRequest.execute(); + if (span != null) { + span.setAttribute( + "bq.rpc.response.routine.id", routineResponse.getRoutineReference().getRoutineId()); + } + return routineResponse; + }); } @Override @@ -1139,31 +991,25 @@ public Tuple> listRoutinesSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span listRoutines = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - listRoutines = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.listRoutines") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "RoutineService") - .setAttribute("bq.rpc.method", "ListRoutines") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", routineListRequest.getPageToken()) - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - ListRoutinesResponse routineResponse = routineListRequest.execute(); - if (listRoutines != null) { - listRoutines.setAttribute("bq.rpc.next_page_token", routineResponse.getNextPageToken()); - listRoutines.end(); - } - Iterable routines = - routineResponse.getRoutines() != null - ? routineResponse.getRoutines() - : ImmutableList.of(); - return Tuple.of(routineResponse.getNextPageToken(), routines); + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.listRoutines", + "RoutineService", + "ListRoutines", + options, + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", routineListRequest.getPageToken()); + } + ListRoutinesResponse routineResponse = routineListRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.next_page_token", routineResponse.getNextPageToken()); + } + Iterable routines = + routineResponse.getRoutines() != null + ? routineResponse.getRoutines() + : ImmutableList.of(); + return Tuple.of(routineResponse.getNextPageToken(), routines); + }); } @Override @@ -1190,24 +1036,14 @@ public boolean deleteRoutineSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span deleteRoutine = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - deleteRoutine = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.listRoutines") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "RoutineService") - .setAttribute("bq.rpc.method", "ListRoutines") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - bqDeleteRequest.execute(); - if (deleteRoutine != null) { - deleteRoutine.end(); - } - return true; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.deleteRoutine", + "RoutineService", + "DeleteRoutine", + span -> { + bqDeleteRequest.execute(); + return true; + }); } @Override @@ -1235,24 +1071,13 @@ public TableDataInsertAllResponse insertAllSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span insertAll = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - insertAll = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.insertAll") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableDataService") - .setAttribute("bq.rpc.method", "InsertAll") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - TableDataInsertAllResponse insertAllResponse = insertAllRequest.execute(); - if (insertAll != null) { - insertAll.end(); - } - return insertAllResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.insertAll", + "TableDataService", + "InsertAll", + span -> { + return insertAllRequest.execute(); + }); } @Override @@ -1286,26 +1111,17 @@ public TableDataList listTableDataSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span listTableData = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - listTableData = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.listTableData") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableDataService") - .setAttribute("bq.rpc.method", "List") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", bqListRequest.getPageToken()) - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - TableDataList bqListResponse = bqListRequest.execute(); - if (listTableData != null) { - listTableData.end(); - } - return bqListResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.listTableData", + "TableDataService", + "List", + options, + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", bqListRequest.getPageToken()); + } + return bqListRequest.execute(); + }); } @Override @@ -1344,25 +1160,16 @@ public TableDataList listTableDataWithRowLimitSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span listTableData = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - listTableData = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.listTableDataWithRowLimit") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableDataService") - .setAttribute("bq.rpc.method", "List") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", bqListRequest.getPageToken()) - .startSpan(); - } - TableDataList bqListResponse = bqListRequest.execute(); - if (listTableData != null) { - listTableData.end(); - } - return bqListResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.listTableDataWithRowLimit", + "TableDataService", + "List", + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", bqListRequest.getPageToken()); + } + return bqListRequest.execute(); + }); } @Override @@ -1394,27 +1201,20 @@ public Job getJobSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getJob = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getJob = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getJob") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "GetJob") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - Job jobResponse = bqGetRequest.execute(); - if (getJob != null) { - getJob.setAttribute("bq.rpc.response.job.id", jobResponse.getId()); - getJob.setAttribute("bq.rpc.response.job.status.state", jobResponse.getStatus().getState()); - getJob.end(); - } - return jobResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.getJob", + "JobService", + "GetJob", + options, + span -> { + Job jobResponse = bqGetRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.job.id", jobResponse.getId()); + span.setAttribute( + "bq.rpc.response.job.status.state", jobResponse.getStatus().getState()); + } + return jobResponse; + }); } @Override @@ -1441,26 +1241,19 @@ public Job getQueryJobSkipExceptionTranslation(String projectId, String jobId, S .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getJob = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getJob = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getQueryJob") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "GetJob") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - Job jobResponse = bqGetRequest.execute(); - if (getJob != null) { - getJob.setAttribute("bq.rpc.response.job.id", jobResponse.getId()); - getJob.setAttribute("bq.rpc.response.job.status.state", jobResponse.getStatus().getState()); - getJob.end(); - } - return jobResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.getQueryJob", + "JobService", + "GetJob", + span -> { + Job jobResponse = bqGetRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.response.job.id", jobResponse.getId()); + span.setAttribute( + "bq.rpc.response.job.status.state", jobResponse.getStatus().getState()); + } + return jobResponse; + }); } @Override @@ -1500,53 +1293,47 @@ public Tuple> listJobsSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span listJobs = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - listJobs = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.listJobs") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "ListJobs") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", listJobsRequest.getPageToken()) - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - JobList jobsList = listJobsRequest.execute(); - if (listJobs != null) { - listJobs.setAttribute("bq.rpc.next_page_token", jobsList.getNextPageToken()); - listJobs.end(); - } - - Iterable jobs = jobsList.getJobs(); - return Tuple.of( - jobsList.getNextPageToken(), - Iterables.transform( - jobs != null ? jobs : ImmutableList.of(), - new Function() { - @Override - public Job apply(JobList.Jobs jobPb) { - JobStatus statusPb = - jobPb.getStatus() != null ? jobPb.getStatus() : new JobStatus(); - if (statusPb.getState() == null) { - statusPb.setState(jobPb.getState()); - } - if (statusPb.getErrorResult() == null) { - statusPb.setErrorResult(jobPb.getErrorResult()); - } - return new Job() - .setConfiguration(jobPb.getConfiguration()) - .setId(jobPb.getId()) - .setJobReference(jobPb.getJobReference()) - .setKind(jobPb.getKind()) - .setStatistics(jobPb.getStatistics()) - .setStatus(statusPb) - .setUserEmail(jobPb.getUserEmail()); - } - })); + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.listJobs", + "JobService", + "ListJobs", + options, + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", listJobsRequest.getPageToken()); + } + JobList jobsList = listJobsRequest.execute(); + if (span != null) { + span.setAttribute("bq.rpc.next_page_token", jobsList.getNextPageToken()); + } + + Iterable jobs = jobsList.getJobs(); + return Tuple.of( + jobsList.getNextPageToken(), + Iterables.transform( + jobs != null ? jobs : ImmutableList.of(), + new Function() { + @Override + public Job apply(JobList.Jobs jobPb) { + JobStatus statusPb = + jobPb.getStatus() != null ? jobPb.getStatus() : new JobStatus(); + if (statusPb.getState() == null) { + statusPb.setState(jobPb.getState()); + } + if (statusPb.getErrorResult() == null) { + statusPb.setErrorResult(jobPb.getErrorResult()); + } + return new Job() + .setConfiguration(jobPb.getConfiguration()) + .setId(jobPb.getId()) + .setJobReference(jobPb.getJobReference()) + .setKind(jobPb.getKind()) + .setStatistics(jobPb.getStatistics()) + .setStatus(statusPb) + .setUserEmail(jobPb.getUserEmail()); + } + })); + }); } @Override @@ -1573,24 +1360,14 @@ public boolean cancelSkipExceptionTranslation(String projectId, String jobId, St .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span cancelJob = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - cancelJob = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.cancelJob") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "CancelJob") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - bqCancelRequest.execute(); - if (cancelJob != null) { - cancelJob.end(); - } - return true; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.cancelJob", + "JobService", + "CancelJob", + span -> { + bqCancelRequest.execute(); + return true; + }); } @Override @@ -1613,24 +1390,14 @@ public boolean deleteJobSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span deleteJob = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - deleteJob = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.deleteJob") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "DeleteJob") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - bqDeleteRequest.execute(); - if (deleteJob != null) { - deleteJob.end(); - } - return true; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.deleteJob", + "JobService", + "DeleteJob", + span -> { + bqDeleteRequest.execute(); + return true; + }); } @Override @@ -1665,27 +1432,17 @@ public GetQueryResultsResponse getQueryResultsSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getQueryResults = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getQueryResults = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getQueryResults") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "GetQueryResults") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", queryRequest.getPageToken()) - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - - GetQueryResultsResponse queryResponse = queryRequest.execute(); - if (getQueryResults != null) { - getQueryResults.end(); - } - return queryResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.getQueryResults", + "JobService", + "GetQueryResults", + options, + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", queryRequest.getPageToken()); + } + return queryRequest.execute(); + }); } @Override @@ -1717,26 +1474,16 @@ public GetQueryResultsResponse getQueryResultsWithRowLimitSkipExceptionTranslati .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getQueryResults = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getQueryResults = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getQueryResultsWithRowLimit") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "GetQueryResults") - .setAttribute("bq.rpc.system", "http") - .setAttribute("bq.rpc.page_token", queryRequest.getPageToken()) - .startSpan(); - } - - GetQueryResultsResponse queryResponse = queryRequest.execute(); - if (getQueryResults != null) { - getQueryResults.end(); - } - return queryResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.getQueryResultsWithRowLimit", + "JobService", + "GetQueryResults", + span -> { + if (span != null) { + span.setAttribute("bq.rpc.page_token", queryRequest.getPageToken()); + } + return queryRequest.execute(); + }); } @Override @@ -1757,25 +1504,13 @@ public QueryResponse queryRpcSkipExceptionTranslation(String projectId, QueryReq .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span getQueryResults = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - getQueryResults = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.queryRpc") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "JobService") - .setAttribute("bq.rpc.method", "Query") - .setAttribute("bq.rpc.system", "http") - .startSpan(); - } - - QueryResponse queryResponse = queryRequest.execute(); - if (getQueryResults != null) { - getQueryResults.end(); - } - return queryResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.queryRpc", + "JobService", + "Query", + span -> { + return queryRequest.execute(); + }); } @Override @@ -1894,26 +1629,14 @@ public Policy getIamPolicySkipExceptionTranslation(String resourceId, Map { + return bqGetRequest.execute(); + }); } @Override @@ -1937,26 +1660,14 @@ public Policy setIamPolicySkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span setIamPolicy = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - setIamPolicy = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.setIamPolicy") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableService") - .setAttribute("bq.rpc.method", "SetIamPolicy") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - - Policy bqSetResponse = bqSetRequest.execute(); - if (setIamPolicy != null) { - setIamPolicy.end(); - } - return bqSetResponse; + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.setIamPolicy", + "TableService", + "SetIamPolicy", + options, + span -> { + return bqSetRequest.execute(); + }); } @Override @@ -1981,26 +1692,69 @@ public TestIamPermissionsResponse testIamPermissionsSkipExceptionTranslation( .getRequestHeaders() .set("x-goog-otel-enabled", this.options.isOpenTelemetryTracingEnabled()); - Span testIamPermissions = null; - if (this.options.isOpenTelemetryTracingEnabled() - && this.options.getOpenTelemetryTracer() != null) { - testIamPermissions = - this.options - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.setIamPolicy") - .setSpanKind(SpanKind.CLIENT) - .setAttribute("bq.rpc.service", "TableService") - .setAttribute("bq.rpc.method", "SetIamPolicy") - .setAttribute("bq.rpc.system", "http") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); + return executeWithSpan( + "com.google.cloud.bigquery.BigQueryRpc.testIamPermissions", + "TableService", + "TestIamPermissions", + options, + span -> { + return bqTestRequest.execute(); + }); + } + + /** + * Helper method to execute an operation with OpenTelemetry tracer span wrapping the execute + * command. + * + * If isOpenTelemetryTracingEnabled == true handles span creation, scope management, and + * cleanup, otherwise only executes the operation. + */ + private T executeWithSpan( + String spanName, + String service, + String method, + Map options, + SpanOperation operation) + throws IOException { + + if (!this.options.isOpenTelemetryTracingEnabled() + || this.options.getOpenTelemetryTracer() == null) { + return operation.execute(null); + } + + SpanBuilder builder = + this.options + .getOpenTelemetryTracer() + .spanBuilder(spanName) + .setSpanKind(SpanKind.CLIENT) + .setAttribute("bq.rpc.service", service) + .setAttribute("bq.rpc.method", method) + .setAttribute("bq.rpc.system", "http"); + + if (options != null) { + builder.setAllAttributes(otelAttributesFromOptions(options)); } - TestIamPermissionsResponse bqTestResponse = bqTestRequest.execute(); - if (testIamPermissions != null) { - testIamPermissions.end(); + Span span = builder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + return operation.execute(span); + } finally { + span.end(); } - return bqTestResponse; + } + + /** Overloaded method for executeWithSpan with null options parameter. */ + private T executeWithSpan( + String spanName, String service, String method, SpanOperation operation) + throws IOException { + return executeWithSpan(spanName, service, method, null, operation); + } + + /** Functional interface for span operations that can throw IOException. */ + @FunctionalInterface + private interface SpanOperation { + T execute(Span span) throws IOException; } private static Attributes otelAttributesFromOptions(Map options) { diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpcTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpcTest.java index 3968cd05e22f..489671461c72 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpcTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpcTest.java @@ -16,11 +16,30 @@ package com.google.cloud.bigquery.spi.v2; import static com.google.common.truth.Truth.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.LowLevelHttpRequest; +import com.google.api.client.http.LowLevelHttpResponse; +import com.google.api.client.json.Json; +import com.google.api.client.testing.http.MockHttpTransport; +import com.google.api.client.testing.http.MockLowLevelHttpRequest; +import com.google.api.client.testing.http.MockLowLevelHttpResponse; import com.google.api.services.bigquery.model.Dataset; import com.google.api.services.bigquery.model.DatasetList; import com.google.api.services.bigquery.model.DatasetReference; +import com.google.cloud.NoCredentials; +import com.google.cloud.bigquery.BigQueryOptions; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import java.util.Collections; +import java.util.HashMap; +import java.util.List; import org.junit.jupiter.api.Test; public class HttpBigQueryRpcTest { @@ -46,4 +65,96 @@ public void testListToDataset() { assertThat(dataset.getLabels()).containsExactly("foo", "bar"); assertThat(dataset.getLocation()).isEqualTo("test-region-1"); } + + @Test + public void testOpenTelemetrySpanCreation() throws Exception { + InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + OpenTelemetrySdk openTelemetry = + OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); + Tracer tracer = openTelemetry.getTracer("test-tracer"); + + HttpTransport mockTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); + response.setStatusCode(200); + response.setContentType(Json.MEDIA_TYPE); + // Return a minimal valid dataset JSON + response.setContent( + "{" + + "\"kind\":\"bigquery#dataset\"," + + "\"id\":\"test-project:test-dataset\"," + + "\"datasetReference\":{" + + " \"projectId\":\"test-project\"," + + " \"datasetId\":\"test-dataset\"" + + "}" + + "}"); + return response; + } + }; + } + }; + + // Create BigQueryOptions with OpenTelemetry enabled and custom transport + BigQueryOptions options = + BigQueryOptions.newBuilder() + .setProjectId("test-project") + .setCredentials(NoCredentials.getInstance()) + .setEnableOpenTelemetryTracing(true) + .setOpenTelemetryTracer(tracer) + .setTransportOptions( + BigQueryOptions.getDefaultHttpTransportOptions().toBuilder() + .setHttpTransportFactory(() -> mockTransport) + .build()) + .build(); + HttpBigQueryRpc rpc = new HttpBigQueryRpc(options); + + Dataset result = rpc.getDataset("test-project", "test-dataset", new HashMap<>()); + + // Verify the RPC call succeeded + assertNotNull(result); + assertEquals("test-project", result.getDatasetReference().getProjectId()); + assertEquals("test-dataset", result.getDatasetReference().getDatasetId()); + + // Verify that spans were created + List spans = spanExporter.getFinishedSpanItems(); + assertThat(spans).isNotEmpty(); + + // Find the RPC span (should be the one we created in executeWithSpan) + SpanData rpcSpan = + spans.stream() + .filter(span -> span.getName().contains("BigQueryRpc.getDataset")) + .findFirst() + .orElse(null); + + assertNotNull(rpcSpan, "Expected to find a span for BigQueryRpc.getDataset"); + + // Verify span attributes are set correctly + assertEquals( + "DatasetService", + rpcSpan + .getAttributes() + .asMap() + .get(io.opentelemetry.api.common.AttributeKey.stringKey("bq.rpc.service"))); + assertEquals( + "GetDataset", + rpcSpan + .getAttributes() + .asMap() + .get(io.opentelemetry.api.common.AttributeKey.stringKey("bq.rpc.method"))); + assertEquals( + "http", + rpcSpan + .getAttributes() + .asMap() + .get(io.opentelemetry.api.common.AttributeKey.stringKey("bq.rpc.system"))); + } }
If isOpenTelemetryTracingEnabled == true handles span creation, scope management, and + * cleanup, otherwise only executes the operation. + */ + private T executeWithSpan( + String spanName, + String service, + String method, + Map options, + SpanOperation operation) + throws IOException { + + if (!this.options.isOpenTelemetryTracingEnabled() + || this.options.getOpenTelemetryTracer() == null) { + return operation.execute(null); + } + + SpanBuilder builder = + this.options + .getOpenTelemetryTracer() + .spanBuilder(spanName) + .setSpanKind(SpanKind.CLIENT) + .setAttribute("bq.rpc.service", service) + .setAttribute("bq.rpc.method", method) + .setAttribute("bq.rpc.system", "http"); + + if (options != null) { + builder.setAllAttributes(otelAttributesFromOptions(options)); } - TestIamPermissionsResponse bqTestResponse = bqTestRequest.execute(); - if (testIamPermissions != null) { - testIamPermissions.end(); + Span span = builder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + return operation.execute(span); + } finally { + span.end(); } - return bqTestResponse; + } + + /** Overloaded method for executeWithSpan with null options parameter. */ + private T executeWithSpan( + String spanName, String service, String method, SpanOperation operation) + throws IOException { + return executeWithSpan(spanName, service, method, null, operation); + } + + /** Functional interface for span operations that can throw IOException. */ + @FunctionalInterface + private interface SpanOperation { + T execute(Span span) throws IOException; } private static Attributes otelAttributesFromOptions(Map options) { diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpcTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpcTest.java index 3968cd05e22f..489671461c72 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpcTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpcTest.java @@ -16,11 +16,30 @@ package com.google.cloud.bigquery.spi.v2; import static com.google.common.truth.Truth.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.LowLevelHttpRequest; +import com.google.api.client.http.LowLevelHttpResponse; +import com.google.api.client.json.Json; +import com.google.api.client.testing.http.MockHttpTransport; +import com.google.api.client.testing.http.MockLowLevelHttpRequest; +import com.google.api.client.testing.http.MockLowLevelHttpResponse; import com.google.api.services.bigquery.model.Dataset; import com.google.api.services.bigquery.model.DatasetList; import com.google.api.services.bigquery.model.DatasetReference; +import com.google.cloud.NoCredentials; +import com.google.cloud.bigquery.BigQueryOptions; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import java.util.Collections; +import java.util.HashMap; +import java.util.List; import org.junit.jupiter.api.Test; public class HttpBigQueryRpcTest { @@ -46,4 +65,96 @@ public void testListToDataset() { assertThat(dataset.getLabels()).containsExactly("foo", "bar"); assertThat(dataset.getLocation()).isEqualTo("test-region-1"); } + + @Test + public void testOpenTelemetrySpanCreation() throws Exception { + InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + OpenTelemetrySdk openTelemetry = + OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); + Tracer tracer = openTelemetry.getTracer("test-tracer"); + + HttpTransport mockTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); + response.setStatusCode(200); + response.setContentType(Json.MEDIA_TYPE); + // Return a minimal valid dataset JSON + response.setContent( + "{" + + "\"kind\":\"bigquery#dataset\"," + + "\"id\":\"test-project:test-dataset\"," + + "\"datasetReference\":{" + + " \"projectId\":\"test-project\"," + + " \"datasetId\":\"test-dataset\"" + + "}" + + "}"); + return response; + } + }; + } + }; + + // Create BigQueryOptions with OpenTelemetry enabled and custom transport + BigQueryOptions options = + BigQueryOptions.newBuilder() + .setProjectId("test-project") + .setCredentials(NoCredentials.getInstance()) + .setEnableOpenTelemetryTracing(true) + .setOpenTelemetryTracer(tracer) + .setTransportOptions( + BigQueryOptions.getDefaultHttpTransportOptions().toBuilder() + .setHttpTransportFactory(() -> mockTransport) + .build()) + .build(); + HttpBigQueryRpc rpc = new HttpBigQueryRpc(options); + + Dataset result = rpc.getDataset("test-project", "test-dataset", new HashMap<>()); + + // Verify the RPC call succeeded + assertNotNull(result); + assertEquals("test-project", result.getDatasetReference().getProjectId()); + assertEquals("test-dataset", result.getDatasetReference().getDatasetId()); + + // Verify that spans were created + List spans = spanExporter.getFinishedSpanItems(); + assertThat(spans).isNotEmpty(); + + // Find the RPC span (should be the one we created in executeWithSpan) + SpanData rpcSpan = + spans.stream() + .filter(span -> span.getName().contains("BigQueryRpc.getDataset")) + .findFirst() + .orElse(null); + + assertNotNull(rpcSpan, "Expected to find a span for BigQueryRpc.getDataset"); + + // Verify span attributes are set correctly + assertEquals( + "DatasetService", + rpcSpan + .getAttributes() + .asMap() + .get(io.opentelemetry.api.common.AttributeKey.stringKey("bq.rpc.service"))); + assertEquals( + "GetDataset", + rpcSpan + .getAttributes() + .asMap() + .get(io.opentelemetry.api.common.AttributeKey.stringKey("bq.rpc.method"))); + assertEquals( + "http", + rpcSpan + .getAttributes() + .asMap() + .get(io.opentelemetry.api.common.AttributeKey.stringKey("bq.rpc.system"))); + } }