HBASE-26472 Adhere to semantic conventions regarding table data operations
Follows the guidance outlined in https://github.com/open-telemetry/opentelemetry-specification/blob/3e380e2/specification/trace/semantic_conventions/database.dm * all table data operations are assumed to be of type CLIENT * populate `db.name` and `db.operation` attributes * name table data operation spans as `db.operation` `db.name`:`db.hbase.table` note: this implementation deviates from the recommended `db.name`.`db.sql.table` and instead uses HBase's native String representation of namespace:tablename. Signed-off-by: Duo Zhang <zhangduo@apache.org> Signed-off-by: Tak Lon (Stephen) Wu <taklwu@apache.org>
This commit is contained in:
parent
a36d41af73
commit
8f5a12f794
|
@ -193,6 +193,11 @@
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hamcrest</groupId>
|
||||||
|
<artifactId>hamcrest-library</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-crypto</artifactId>
|
<artifactId>commons-crypto</artifactId>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/**
|
/*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
* or more contributor license agreements. See the NOTICE file
|
* or more contributor license agreements. See the NOTICE file
|
||||||
* distributed with this work for additional information
|
* distributed with this work for additional information
|
||||||
|
@ -27,6 +27,7 @@ import static org.apache.hadoop.hbase.trace.TraceUtil.tracedFuture;
|
||||||
import static org.apache.hadoop.hbase.trace.TraceUtil.tracedFutures;
|
import static org.apache.hadoop.hbase.trace.TraceUtil.tracedFutures;
|
||||||
import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
|
import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.trace.Span;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -36,6 +37,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.hbase.CompareOperator;
|
import org.apache.hadoop.hbase.CompareOperator;
|
||||||
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
||||||
|
@ -44,9 +46,11 @@ import org.apache.hadoop.hbase.HRegionLocation;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.hadoop.hbase.client.AsyncRpcRetryingCallerFactory.SingleRequestCallerBuilder;
|
import org.apache.hadoop.hbase.client.AsyncRpcRetryingCallerFactory.SingleRequestCallerBuilder;
|
||||||
import org.apache.hadoop.hbase.client.ConnectionUtils.Converter;
|
import org.apache.hadoop.hbase.client.ConnectionUtils.Converter;
|
||||||
|
import org.apache.hadoop.hbase.client.trace.TableOperationSpanBuilder;
|
||||||
import org.apache.hadoop.hbase.filter.Filter;
|
import org.apache.hadoop.hbase.filter.Filter;
|
||||||
import org.apache.hadoop.hbase.io.TimeRange;
|
import org.apache.hadoop.hbase.io.TimeRange;
|
||||||
import org.apache.hadoop.hbase.ipc.HBaseRpcController;
|
import org.apache.hadoop.hbase.ipc.HBaseRpcController;
|
||||||
|
import org.apache.hadoop.hbase.trace.HBaseSemanticAttributes;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
import org.apache.hadoop.hbase.util.ReflectionUtils;
|
import org.apache.hadoop.hbase.util.ReflectionUtils;
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
@ -218,37 +222,49 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
.replicaId(replicaId).call();
|
.replicaId(replicaId).call();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TableOperationSpanBuilder newTableOperationSpanBuilder() {
|
||||||
|
return new TableOperationSpanBuilder().setTableName(tableName);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Result> get(Get get) {
|
public CompletableFuture<Result> get(Get get) {
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(get);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> timelineConsistentRead(conn.getLocator(), tableName, get, get.getRow(),
|
() -> timelineConsistentRead(conn.getLocator(), tableName, get, get.getRow(),
|
||||||
RegionLocateType.CURRENT, replicaId -> get(get, replicaId), readRpcTimeoutNs,
|
RegionLocateType.CURRENT, replicaId -> get(get, replicaId), readRpcTimeoutNs,
|
||||||
conn.connConf.getPrimaryCallTimeoutNs(), retryTimer, conn.getConnectionMetrics()),
|
conn.connConf.getPrimaryCallTimeoutNs(), retryTimer, conn.getConnectionMetrics()),
|
||||||
"AsyncTable.get", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> put(Put put) {
|
public CompletableFuture<Void> put(Put put) {
|
||||||
validatePut(put, conn.connConf.getMaxKeyValueSize());
|
validatePut(put, conn.connConf.getMaxKeyValueSize());
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(put);
|
||||||
return tracedFuture(() -> this.<Void, Put> newCaller(put, writeRpcTimeoutNs)
|
return tracedFuture(() -> this.<Void, Put> newCaller(put, writeRpcTimeoutNs)
|
||||||
.action((controller, loc, stub) -> RawAsyncTableImpl.<Put> voidMutate(controller, loc, stub,
|
.action((controller, loc, stub) -> RawAsyncTableImpl.<Put> voidMutate(controller, loc, stub,
|
||||||
put, RequestConverter::buildMutateRequest))
|
put, RequestConverter::buildMutateRequest))
|
||||||
.call(), "AsyncTable.put", tableName);
|
.call(), supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> delete(Delete delete) {
|
public CompletableFuture<Void> delete(Delete delete) {
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(delete);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> this.<Void, Delete> newCaller(delete, writeRpcTimeoutNs)
|
() -> this.<Void, Delete> newCaller(delete, writeRpcTimeoutNs)
|
||||||
.action((controller, loc, stub) -> RawAsyncTableImpl.<Delete> voidMutate(controller, loc,
|
.action((controller, loc, stub) -> RawAsyncTableImpl.<Delete> voidMutate(controller, loc,
|
||||||
stub, delete, RequestConverter::buildMutateRequest))
|
stub, delete, RequestConverter::buildMutateRequest))
|
||||||
.call(),
|
.call(),
|
||||||
"AsyncTable.delete", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Result> append(Append append) {
|
public CompletableFuture<Result> append(Append append) {
|
||||||
checkHasFamilies(append);
|
checkHasFamilies(append);
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(append);
|
||||||
return tracedFuture(() -> {
|
return tracedFuture(() -> {
|
||||||
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
||||||
long nonce = conn.getNonceGenerator().newNonce();
|
long nonce = conn.getNonceGenerator().newNonce();
|
||||||
|
@ -257,12 +273,14 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
controller, loc, stub, append, RequestConverter::buildMutateRequest,
|
controller, loc, stub, append, RequestConverter::buildMutateRequest,
|
||||||
RawAsyncTableImpl::toResult))
|
RawAsyncTableImpl::toResult))
|
||||||
.call();
|
.call();
|
||||||
}, "AsyncTable.append", tableName);
|
}, supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Result> increment(Increment increment) {
|
public CompletableFuture<Result> increment(Increment increment) {
|
||||||
checkHasFamilies(increment);
|
checkHasFamilies(increment);
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(increment);
|
||||||
return tracedFuture(() -> {
|
return tracedFuture(() -> {
|
||||||
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
||||||
long nonce = conn.getNonceGenerator().newNonce();
|
long nonce = conn.getNonceGenerator().newNonce();
|
||||||
|
@ -271,7 +289,7 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
controller, loc, stub, increment, RequestConverter::buildMutateRequest,
|
controller, loc, stub, increment, RequestConverter::buildMutateRequest,
|
||||||
RawAsyncTableImpl::toResult))
|
RawAsyncTableImpl::toResult))
|
||||||
.call();
|
.call();
|
||||||
}, "AsyncTable.increment", tableName);
|
}, supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class CheckAndMutateBuilderImpl implements CheckAndMutateBuilder {
|
private final class CheckAndMutateBuilderImpl implements CheckAndMutateBuilder {
|
||||||
|
@ -329,6 +347,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
public CompletableFuture<Boolean> thenPut(Put put) {
|
public CompletableFuture<Boolean> thenPut(Put put) {
|
||||||
validatePut(put, conn.connConf.getMaxKeyValueSize());
|
validatePut(put, conn.connConf.getMaxKeyValueSize());
|
||||||
preCheck();
|
preCheck();
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, put.getPriority(), rpcTimeoutNs)
|
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, put.getPriority(), rpcTimeoutNs)
|
||||||
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, put,
|
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, put,
|
||||||
|
@ -336,12 +356,14 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
null, timeRange, p, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
null, timeRange, p, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||||
(c, r) -> r.getProcessed()))
|
(c, r) -> r.getProcessed()))
|
||||||
.call(),
|
.call(),
|
||||||
"AsyncTable.CheckAndMutateBuilder.thenPut", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> thenDelete(Delete delete) {
|
public CompletableFuture<Boolean> thenDelete(Delete delete) {
|
||||||
preCheck();
|
preCheck();
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
|
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
|
||||||
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, delete,
|
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, delete,
|
||||||
|
@ -349,23 +371,25 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
null, timeRange, d, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
null, timeRange, d, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||||
(c, r) -> r.getProcessed()))
|
(c, r) -> r.getProcessed()))
|
||||||
.call(),
|
.call(),
|
||||||
"AsyncTable.CheckAndMutateBuilder.thenDelete", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> thenMutate(RowMutations mutation) {
|
public CompletableFuture<Boolean> thenMutate(RowMutations mutations) {
|
||||||
preCheck();
|
preCheck();
|
||||||
validatePutsInRowMutations(mutation, conn.connConf.getMaxKeyValueSize());
|
validatePutsInRowMutations(mutations, conn.connConf.getMaxKeyValueSize());
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> RawAsyncTableImpl.this
|
() -> RawAsyncTableImpl.this
|
||||||
.<Boolean> newCaller(row, mutation.getMaxPriority(), rpcTimeoutNs)
|
.<Boolean> newCaller(row, mutations.getMaxPriority(), rpcTimeoutNs)
|
||||||
.action((controller, loc, stub) -> RawAsyncTableImpl.this.mutateRow(controller, loc, stub,
|
.action((controller, loc, stub) -> RawAsyncTableImpl.this.mutateRow(controller, loc, stub,
|
||||||
mutation,
|
mutations,
|
||||||
(rn, rm) -> RequestConverter.buildMultiRequest(rn, row, family, qualifier, op, value,
|
(rn, rm) -> RequestConverter.buildMultiRequest(rn, row, family, qualifier, op, value,
|
||||||
null, timeRange, rm, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
null, timeRange, rm, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||||
CheckAndMutateResult::isSuccess))
|
CheckAndMutateResult::isSuccess))
|
||||||
.call(),
|
.call(),
|
||||||
"AsyncTable.CheckAndMutateBuilder.thenMutate", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,6 +421,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> thenPut(Put put) {
|
public CompletableFuture<Boolean> thenPut(Put put) {
|
||||||
validatePut(put, conn.connConf.getMaxKeyValueSize());
|
validatePut(put, conn.connConf.getMaxKeyValueSize());
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, put.getPriority(), rpcTimeoutNs)
|
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, put.getPriority(), rpcTimeoutNs)
|
||||||
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc,
|
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc,
|
||||||
|
@ -405,11 +431,13 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
filter, timeRange, p, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
filter, timeRange, p, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||||
(c, r) -> r.getProcessed()))
|
(c, r) -> r.getProcessed()))
|
||||||
.call(),
|
.call(),
|
||||||
"AsyncTable.CheckAndMutateWithFilterBuilder.thenPut", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> thenDelete(Delete delete) {
|
public CompletableFuture<Boolean> thenDelete(Delete delete) {
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
|
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
|
||||||
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, delete,
|
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, delete,
|
||||||
|
@ -417,22 +445,24 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
timeRange, d, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
timeRange, d, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||||
(c, r) -> r.getProcessed()))
|
(c, r) -> r.getProcessed()))
|
||||||
.call(),
|
.call(),
|
||||||
"AsyncTable.CheckAndMutateWithFilterBuilder.thenDelete", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> thenMutate(RowMutations mutation) {
|
public CompletableFuture<Boolean> thenMutate(RowMutations mutations) {
|
||||||
validatePutsInRowMutations(mutation, conn.connConf.getMaxKeyValueSize());
|
validatePutsInRowMutations(mutations, conn.connConf.getMaxKeyValueSize());
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> RawAsyncTableImpl.this
|
() -> RawAsyncTableImpl.this
|
||||||
.<Boolean> newCaller(row, mutation.getMaxPriority(), rpcTimeoutNs)
|
.<Boolean> newCaller(row, mutations.getMaxPriority(), rpcTimeoutNs)
|
||||||
.action((controller, loc, stub) -> RawAsyncTableImpl.this.mutateRow(controller, loc, stub,
|
.action((controller, loc, stub) -> RawAsyncTableImpl.this.mutateRow(controller, loc, stub,
|
||||||
mutation,
|
mutations,
|
||||||
(rn, rm) -> RequestConverter.buildMultiRequest(rn, row, null, null, null, null, filter,
|
(rn, rm) -> RequestConverter.buildMultiRequest(rn, row, null, null, null, null, filter,
|
||||||
timeRange, rm, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
timeRange, rm, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||||
CheckAndMutateResult::isSuccess))
|
CheckAndMutateResult::isSuccess))
|
||||||
.call(),
|
.call(),
|
||||||
"AsyncTable.CheckAndMutateWithFilterBuilder.thenMutate", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,6 +473,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<CheckAndMutateResult> checkAndMutate(CheckAndMutate checkAndMutate) {
|
public CompletableFuture<CheckAndMutateResult> checkAndMutate(CheckAndMutate checkAndMutate) {
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(checkAndMutate);
|
||||||
return tracedFuture(() -> {
|
return tracedFuture(() -> {
|
||||||
if (checkAndMutate.getAction() instanceof Put ||
|
if (checkAndMutate.getAction() instanceof Put ||
|
||||||
checkAndMutate.getAction() instanceof Delete ||
|
checkAndMutate.getAction() instanceof Delete ||
|
||||||
|
@ -488,16 +520,18 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
"CheckAndMutate doesn't support " + checkAndMutate.getAction().getClass().getName()));
|
"CheckAndMutate doesn't support " + checkAndMutate.getAction().getClass().getName()));
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
}, "AsyncTable.checkAndMutate", tableName);
|
}, supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CompletableFuture<CheckAndMutateResult>>
|
public List<CompletableFuture<CheckAndMutateResult>>
|
||||||
checkAndMutate(List<CheckAndMutate> checkAndMutates) {
|
checkAndMutate(List<CheckAndMutate> checkAndMutates) {
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(checkAndMutates);
|
||||||
return tracedFutures(
|
return tracedFutures(
|
||||||
() -> batch(checkAndMutates, rpcTimeoutNs).stream()
|
() -> batch(checkAndMutates, rpcTimeoutNs).stream()
|
||||||
.map(f -> f.thenApply(r -> (CheckAndMutateResult) r)).collect(toList()),
|
.map(f -> f.thenApply(r -> (CheckAndMutateResult) r)).collect(toList()),
|
||||||
"AsyncTable.checkAndMutateList", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need the MultiRequest when constructing the org.apache.hadoop.hbase.client.MultiResponse,
|
// We need the MultiRequest when constructing the org.apache.hadoop.hbase.client.MultiResponse,
|
||||||
|
@ -548,6 +582,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
validatePutsInRowMutations(mutations, conn.connConf.getMaxKeyValueSize());
|
validatePutsInRowMutations(mutations, conn.connConf.getMaxKeyValueSize());
|
||||||
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
||||||
long nonce = conn.getNonceGenerator().newNonce();
|
long nonce = conn.getNonceGenerator().newNonce();
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(mutations);
|
||||||
return tracedFuture(
|
return tracedFuture(
|
||||||
() -> this
|
() -> this
|
||||||
.<Result> newCaller(mutations.getRow(), mutations.getMaxPriority(), writeRpcTimeoutNs)
|
.<Result> newCaller(mutations.getRow(), mutations.getMaxPriority(), writeRpcTimeoutNs)
|
||||||
|
@ -555,7 +591,7 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
mutations, (rn, rm) -> RequestConverter.buildMultiRequest(rn, rm, nonceGroup, nonce),
|
mutations, (rn, rm) -> RequestConverter.buildMultiRequest(rn, rm, nonceGroup, nonce),
|
||||||
resp -> resp))
|
resp -> resp))
|
||||||
.call(),
|
.call(),
|
||||||
"AsyncTable.mutateRow", tableName);
|
supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Scan setDefaultScanConfig(Scan scan) {
|
private Scan setDefaultScanConfig(Scan scan) {
|
||||||
|
@ -591,6 +627,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<List<Result>> scanAll(Scan scan) {
|
public CompletableFuture<List<Result>> scanAll(Scan scan) {
|
||||||
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(scan);
|
||||||
return tracedFuture(() -> {
|
return tracedFuture(() -> {
|
||||||
CompletableFuture<List<Result>> future = new CompletableFuture<>();
|
CompletableFuture<List<Result>> future = new CompletableFuture<>();
|
||||||
List<Result> scanResults = new ArrayList<>();
|
List<Result> scanResults = new ArrayList<>();
|
||||||
|
@ -612,27 +650,35 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return future;
|
return future;
|
||||||
}, "AsyncTable.scanAll", tableName);
|
}, supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CompletableFuture<Result>> get(List<Get> gets) {
|
public List<CompletableFuture<Result>> get(List<Get> gets) {
|
||||||
return tracedFutures(() -> batch(gets, readRpcTimeoutNs), "AsyncTable.getList", tableName);
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(gets);
|
||||||
|
return tracedFutures(() -> batch(gets, readRpcTimeoutNs), supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CompletableFuture<Void>> put(List<Put> puts) {
|
public List<CompletableFuture<Void>> put(List<Put> puts) {
|
||||||
return tracedFutures(() -> voidMutate(puts), "AsyncTable.putList", tableName);
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(puts);
|
||||||
|
return tracedFutures(() -> voidMutate(puts), supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CompletableFuture<Void>> delete(List<Delete> deletes) {
|
public List<CompletableFuture<Void>> delete(List<Delete> deletes) {
|
||||||
return tracedFutures(() -> voidMutate(deletes), "AsyncTable.deleteList", tableName);
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(deletes);
|
||||||
|
return tracedFutures(() -> voidMutate(deletes), supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> List<CompletableFuture<T>> batch(List<? extends Row> actions) {
|
public <T> List<CompletableFuture<T>> batch(List<? extends Row> actions) {
|
||||||
return tracedFutures(() -> batch(actions, rpcTimeoutNs), "AsyncTable.batch", tableName);
|
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||||
|
.setOperation(actions);
|
||||||
|
return tracedFutures(() -> batch(actions, rpcTimeoutNs), supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CompletableFuture<Void>> voidMutate(List<? extends Row> actions) {
|
private List<CompletableFuture<Void>> voidMutate(List<? extends Row> actions) {
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.hbase.client.trace;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.DB_NAME;
|
||||||
|
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.DB_OPERATION;
|
||||||
|
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.NAMESPACE_KEY;
|
||||||
|
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.TABLE_KEY;
|
||||||
|
import io.opentelemetry.api.common.AttributeKey;
|
||||||
|
import io.opentelemetry.api.trace.Span;
|
||||||
|
import io.opentelemetry.api.trace.SpanBuilder;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.Append;
|
||||||
|
import org.apache.hadoop.hbase.client.CheckAndMutate;
|
||||||
|
import org.apache.hadoop.hbase.client.Delete;
|
||||||
|
import org.apache.hadoop.hbase.client.Get;
|
||||||
|
import org.apache.hadoop.hbase.client.Increment;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
|
import org.apache.hadoop.hbase.client.RegionCoprocessorServiceExec;
|
||||||
|
import org.apache.hadoop.hbase.client.Row;
|
||||||
|
import org.apache.hadoop.hbase.client.RowMutations;
|
||||||
|
import org.apache.hadoop.hbase.client.Scan;
|
||||||
|
import org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.Operation;
|
||||||
|
import org.apache.hadoop.hbase.trace.TraceUtil;
|
||||||
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct {@link io.opentelemetry.api.trace.Span} instances originating from
|
||||||
|
* "table operations" -- the verbs in our public API that interact with data in tables.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
public class TableOperationSpanBuilder implements Supplier<Span> {
|
||||||
|
|
||||||
|
// n.b. The results of this class are tested implicitly by way of the likes of
|
||||||
|
// `TestAsyncTableTracing` and friends.
|
||||||
|
|
||||||
|
private static final String unknown = "UNKNOWN";
|
||||||
|
|
||||||
|
private TableName tableName;
|
||||||
|
private final Map<AttributeKey<?>, Object> attributes = new HashMap<>();
|
||||||
|
|
||||||
|
@Override public Span get() {
|
||||||
|
return build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableOperationSpanBuilder setOperation(final Scan scan) {
|
||||||
|
return setOperation(valueFrom(scan));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableOperationSpanBuilder setOperation(final Row row) {
|
||||||
|
return setOperation(valueFrom(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public TableOperationSpanBuilder setOperation(final Collection<? extends Row> operations) {
|
||||||
|
return setOperation(Operation.BATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableOperationSpanBuilder setOperation(final Operation operation) {
|
||||||
|
attributes.put(DB_OPERATION, operation.name());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableOperationSpanBuilder setTableName(final TableName tableName) {
|
||||||
|
this.tableName = tableName;
|
||||||
|
attributes.put(NAMESPACE_KEY, tableName.getNamespaceAsString());
|
||||||
|
attributes.put(DB_NAME, tableName.getNamespaceAsString());
|
||||||
|
attributes.put(TABLE_KEY, tableName.getNameAsString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Span build() {
|
||||||
|
final String name = attributes.getOrDefault(DB_OPERATION, unknown)
|
||||||
|
+ " "
|
||||||
|
+ (tableName != null ? tableName.getNameWithNamespaceInclAsString() : unknown);
|
||||||
|
final SpanBuilder builder = TraceUtil.getGlobalTracer()
|
||||||
|
.spanBuilder(name)
|
||||||
|
// TODO: what about clients embedded in Master/RegionServer/Gateways/&c?
|
||||||
|
.setSpanKind(SpanKind.CLIENT);
|
||||||
|
attributes.forEach((k, v) -> builder.setAttribute((AttributeKey<? super Object>) k, v));
|
||||||
|
return builder.startSpan();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operation valueFrom(final Scan scan) {
|
||||||
|
if (scan == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Operation.SCAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operation valueFrom(final Row row) {
|
||||||
|
if (row == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (row instanceof Append) {
|
||||||
|
return Operation.APPEND;
|
||||||
|
}
|
||||||
|
if (row instanceof CheckAndMutate) {
|
||||||
|
return Operation.CHECK_AND_MUTATE;
|
||||||
|
}
|
||||||
|
if (row instanceof Delete) {
|
||||||
|
return Operation.DELETE;
|
||||||
|
}
|
||||||
|
if (row instanceof Get) {
|
||||||
|
return Operation.GET;
|
||||||
|
}
|
||||||
|
if (row instanceof Increment) {
|
||||||
|
return Operation.INCREMENT;
|
||||||
|
}
|
||||||
|
if (row instanceof Put) {
|
||||||
|
return Operation.PUT;
|
||||||
|
}
|
||||||
|
if (row instanceof RegionCoprocessorServiceExec) {
|
||||||
|
return Operation.COPROC_EXEC;
|
||||||
|
}
|
||||||
|
if (row instanceof RowMutations) {
|
||||||
|
return Operation.BATCH;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,15 +17,24 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hbase.client;
|
package org.apache.hadoop.hbase.client;
|
||||||
|
|
||||||
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.NAMESPACE_KEY;
|
import static org.apache.hadoop.hbase.client.trace.hamcrest.AttributesMatchers.containsEntry;
|
||||||
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.TABLE_KEY;
|
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasAttributes;
|
||||||
|
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded;
|
||||||
|
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasKind;
|
||||||
|
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasName;
|
||||||
|
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasStatusWithCode;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.api.trace.SpanKind;
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
import io.opentelemetry.api.trace.StatusCode;
|
import io.opentelemetry.api.trace.StatusCode;
|
||||||
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
|
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
|
||||||
|
@ -43,14 +52,18 @@ import org.apache.hadoop.hbase.CellBuilderType;
|
||||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
import org.apache.hadoop.hbase.HBaseConfiguration;
|
import org.apache.hadoop.hbase.HBaseConfiguration;
|
||||||
import org.apache.hadoop.hbase.HRegionLocation;
|
import org.apache.hadoop.hbase.HRegionLocation;
|
||||||
|
import org.apache.hadoop.hbase.MatcherPredicate;
|
||||||
import org.apache.hadoop.hbase.ServerName;
|
import org.apache.hadoop.hbase.ServerName;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.hadoop.hbase.Waiter;
|
import org.apache.hadoop.hbase.Waiter;
|
||||||
|
import org.apache.hadoop.hbase.filter.PrefixFilter;
|
||||||
import org.apache.hadoop.hbase.ipc.HBaseRpcController;
|
import org.apache.hadoop.hbase.ipc.HBaseRpcController;
|
||||||
import org.apache.hadoop.hbase.security.UserProvider;
|
import org.apache.hadoop.hbase.security.UserProvider;
|
||||||
import org.apache.hadoop.hbase.testclassification.ClientTests;
|
import org.apache.hadoop.hbase.testclassification.ClientTests;
|
||||||
import org.apache.hadoop.hbase.testclassification.MediumTests;
|
import org.apache.hadoop.hbase.testclassification.MediumTests;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
import org.hamcrest.core.IsAnything;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
|
@ -59,10 +72,8 @@ import org.junit.Test;
|
||||||
import org.junit.experimental.categories.Category;
|
import org.junit.experimental.categories.Category;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
|
import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
|
||||||
import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
|
import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
|
||||||
|
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService;
|
||||||
|
@ -135,11 +146,17 @@ public class TestAsyncTableTracing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||||
ClientProtos.MultiResponse resp =
|
ClientProtos.MultiRequest req = invocation.getArgument(1);
|
||||||
ClientProtos.MultiResponse.newBuilder()
|
ClientProtos.MultiResponse.Builder builder = ClientProtos.MultiResponse.newBuilder();
|
||||||
.addRegionActionResult(RegionActionResult.newBuilder().addResultOrException(
|
for (ClientProtos.RegionAction regionAction : req.getRegionActionList()) {
|
||||||
ResultOrException.newBuilder().setResult(ProtobufUtil.toResult(new Result()))))
|
RegionActionResult.Builder raBuilder = RegionActionResult.newBuilder();
|
||||||
.build();
|
for (ClientProtos.Action ignored : regionAction.getActionList()) {
|
||||||
|
raBuilder.addResultOrException(
|
||||||
|
ResultOrException.newBuilder().setResult(ProtobufUtil.toResult(new Result())));
|
||||||
|
}
|
||||||
|
builder.addRegionActionResult(raBuilder);
|
||||||
|
}
|
||||||
|
ClientProtos.MultiResponse resp = builder.build();
|
||||||
RpcCallback<ClientProtos.MultiResponse> done = invocation.getArgument(2);
|
RpcCallback<ClientProtos.MultiResponse> done = invocation.getArgument(2);
|
||||||
ForkJoinPool.commonPool().execute(() -> done.run(resp));
|
ForkJoinPool.commonPool().execute(() -> done.run(resp));
|
||||||
return null;
|
return null;
|
||||||
|
@ -219,49 +236,73 @@ public class TestAsyncTableTracing {
|
||||||
Closeables.close(conn, true);
|
Closeables.close(conn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTrace(String methodName) {
|
/**
|
||||||
Waiter.waitFor(CONF, 1000,
|
* All {@link Span}s generated from table data access operations over {@code tableName} should
|
||||||
() -> traceRule.getSpans().stream()
|
* include these attributes.
|
||||||
.anyMatch(span -> span.getName().equals("AsyncTable." + methodName) &&
|
*/
|
||||||
span.getKind() == SpanKind.INTERNAL && span.hasEnded()));
|
private static Matcher<SpanData> buildBaseAttributesMatcher(TableName tableName) {
|
||||||
SpanData data = traceRule.getSpans().stream()
|
return hasAttributes(allOf(
|
||||||
.filter(s -> s.getName().equals("AsyncTable." + methodName)).findFirst().get();
|
containsEntry("db.name", tableName.getNamespaceAsString()),
|
||||||
assertEquals(StatusCode.OK, data.getStatus().getStatusCode());
|
containsEntry("db.hbase.namespace", tableName.getNamespaceAsString()),
|
||||||
TableName tableName = table.getName();
|
containsEntry("db.hbase.table", tableName.getNameAsString())));
|
||||||
assertEquals(tableName.getNamespaceAsString(), data.getAttributes().get(NAMESPACE_KEY));
|
}
|
||||||
assertEquals(tableName.getNameAsString(), data.getAttributes().get(TABLE_KEY));
|
|
||||||
|
private void assertTrace(String tableOperation) {
|
||||||
|
assertTrace(tableOperation, new IsAnything<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertTrace(String tableOperation, Matcher<SpanData> matcher) {
|
||||||
|
final TableName tableName = table.getName();
|
||||||
|
final Matcher<SpanData> spanLocator = allOf(
|
||||||
|
hasName(containsString(tableOperation)), hasEnded());
|
||||||
|
final String expectedName = tableOperation + " " + tableName.getNameWithNamespaceInclAsString();
|
||||||
|
|
||||||
|
Waiter.waitFor(CONF, 1000, new MatcherPredicate<>(
|
||||||
|
"waiting for span to emit",
|
||||||
|
() -> traceRule.getSpans(), hasItem(spanLocator)));
|
||||||
|
SpanData data = traceRule.getSpans()
|
||||||
|
.stream()
|
||||||
|
.filter(spanLocator::matches)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(AssertionError::new);
|
||||||
|
assertThat(data, allOf(
|
||||||
|
hasName(expectedName),
|
||||||
|
hasKind(SpanKind.CLIENT),
|
||||||
|
hasStatusWithCode(StatusCode.OK),
|
||||||
|
buildBaseAttributesMatcher(tableName),
|
||||||
|
matcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExists() {
|
public void testExists() {
|
||||||
table.exists(new Get(Bytes.toBytes(0))).join();
|
table.exists(new Get(Bytes.toBytes(0))).join();
|
||||||
assertTrace("get");
|
assertTrace("GET");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGet() {
|
public void testGet() {
|
||||||
table.get(new Get(Bytes.toBytes(0))).join();
|
table.get(new Get(Bytes.toBytes(0))).join();
|
||||||
assertTrace("get");
|
assertTrace("GET");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPut() {
|
public void testPut() {
|
||||||
table.put(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("cq"),
|
table.put(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("cq"),
|
||||||
Bytes.toBytes("v"))).join();
|
Bytes.toBytes("v"))).join();
|
||||||
assertTrace("put");
|
assertTrace("PUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDelete() {
|
public void testDelete() {
|
||||||
table.delete(new Delete(Bytes.toBytes(0))).join();
|
table.delete(new Delete(Bytes.toBytes(0))).join();
|
||||||
assertTrace("delete");
|
assertTrace("DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAppend() {
|
public void testAppend() {
|
||||||
table.append(new Append(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("cq"),
|
table.append(new Append(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("cq"),
|
||||||
Bytes.toBytes("v"))).join();
|
Bytes.toBytes("v"))).join();
|
||||||
assertTrace("append");
|
assertTrace("APPEND");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -270,21 +311,21 @@ public class TestAsyncTableTracing {
|
||||||
.increment(
|
.increment(
|
||||||
new Increment(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("cq"), 1))
|
new Increment(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("cq"), 1))
|
||||||
.join();
|
.join();
|
||||||
assertTrace("increment");
|
assertTrace("INCREMENT");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncrementColumnValue1() {
|
public void testIncrementColumnValue1() {
|
||||||
table.incrementColumnValue(Bytes.toBytes(0), Bytes.toBytes("cf"), Bytes.toBytes("cq"), 1)
|
table.incrementColumnValue(Bytes.toBytes(0), Bytes.toBytes("cf"), Bytes.toBytes("cq"), 1)
|
||||||
.join();
|
.join();
|
||||||
assertTrace("increment");
|
assertTrace("INCREMENT");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncrementColumnValue2() {
|
public void testIncrementColumnValue2() {
|
||||||
table.incrementColumnValue(Bytes.toBytes(0), Bytes.toBytes("cf"), Bytes.toBytes("cq"), 1,
|
table.incrementColumnValue(Bytes.toBytes(0), Bytes.toBytes("cf"), Bytes.toBytes("cq"), 1,
|
||||||
Durability.ASYNC_WAL).join();
|
Durability.ASYNC_WAL).join();
|
||||||
assertTrace("increment");
|
assertTrace("INCREMENT");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -292,7 +333,7 @@ public class TestAsyncTableTracing {
|
||||||
table.checkAndMutate(CheckAndMutate.newBuilder(Bytes.toBytes(0))
|
table.checkAndMutate(CheckAndMutate.newBuilder(Bytes.toBytes(0))
|
||||||
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
|
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
|
||||||
.build(new Delete(Bytes.toBytes(0)))).join();
|
.build(new Delete(Bytes.toBytes(0)))).join();
|
||||||
assertTrace("checkAndMutate");
|
assertTrace("CHECK_AND_MUTATE");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -302,7 +343,7 @@ public class TestAsyncTableTracing {
|
||||||
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
|
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
|
||||||
.build(new Delete(Bytes.toBytes(0))))).toArray(new CompletableFuture[0]))
|
.build(new Delete(Bytes.toBytes(0))))).toArray(new CompletableFuture[0]))
|
||||||
.join();
|
.join();
|
||||||
assertTrace("checkAndMutateList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -310,19 +351,100 @@ public class TestAsyncTableTracing {
|
||||||
table.checkAndMutateAll(Arrays.asList(CheckAndMutate.newBuilder(Bytes.toBytes(0))
|
table.checkAndMutateAll(Arrays.asList(CheckAndMutate.newBuilder(Bytes.toBytes(0))
|
||||||
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
|
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
|
||||||
.build(new Delete(Bytes.toBytes(0))))).join();
|
.build(new Delete(Bytes.toBytes(0))))).join();
|
||||||
assertTrace("checkAndMutateList");
|
assertTrace("BATCH");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testCheckAndMutateBuilder(Row op) {
|
||||||
|
AsyncTable.CheckAndMutateBuilder builder =
|
||||||
|
table.checkAndMutate(Bytes.toBytes(0), Bytes.toBytes("cf"))
|
||||||
|
.qualifier(Bytes.toBytes("cq"))
|
||||||
|
.ifEquals(Bytes.toBytes("v"));
|
||||||
|
if (op instanceof Put) {
|
||||||
|
Put put = (Put) op;
|
||||||
|
builder.thenPut(put).join();
|
||||||
|
} else if (op instanceof Delete) {
|
||||||
|
Delete delete = (Delete) op;
|
||||||
|
builder.thenDelete(delete).join();
|
||||||
|
} else if (op instanceof RowMutations) {
|
||||||
|
RowMutations mutations = (RowMutations) op;
|
||||||
|
builder.thenMutate(mutations).join();
|
||||||
|
} else {
|
||||||
|
fail("unsupported CheckAndPut operation " + op);
|
||||||
|
}
|
||||||
|
assertTrace("CHECK_AND_MUTATE");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAndMutateBuilderThenPut() {
|
||||||
|
Put put = new Put(Bytes.toBytes(0))
|
||||||
|
.addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"), Bytes.toBytes("v"));
|
||||||
|
testCheckAndMutateBuilder(put);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAndMutateBuilderThenDelete() {
|
||||||
|
testCheckAndMutateBuilder(new Delete(Bytes.toBytes(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAndMutateBuilderThenMutations() throws IOException {
|
||||||
|
RowMutations mutations = new RowMutations(Bytes.toBytes(0))
|
||||||
|
.add(new Put(Bytes.toBytes(0))
|
||||||
|
.addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"), Bytes.toBytes("v")))
|
||||||
|
.add(new Delete(Bytes.toBytes(0)));
|
||||||
|
testCheckAndMutateBuilder(mutations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testCheckAndMutateWithFilterBuilder(Row op) {
|
||||||
|
// use of `PrefixFilter` is completely arbitrary here.
|
||||||
|
AsyncTable.CheckAndMutateWithFilterBuilder builder =
|
||||||
|
table.checkAndMutate(Bytes.toBytes(0), new PrefixFilter(Bytes.toBytes(0)));
|
||||||
|
if (op instanceof Put) {
|
||||||
|
Put put = (Put) op;
|
||||||
|
builder.thenPut(put).join();
|
||||||
|
} else if (op instanceof Delete) {
|
||||||
|
Delete delete = (Delete) op;
|
||||||
|
builder.thenDelete(delete).join();
|
||||||
|
} else if (op instanceof RowMutations) {
|
||||||
|
RowMutations mutations = (RowMutations) op;
|
||||||
|
builder.thenMutate(mutations).join();
|
||||||
|
} else {
|
||||||
|
fail("unsupported CheckAndPut operation " + op);
|
||||||
|
}
|
||||||
|
assertTrace("CHECK_AND_MUTATE");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAndMutateWithFilterBuilderThenPut() {
|
||||||
|
Put put = new Put(Bytes.toBytes(0))
|
||||||
|
.addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"), Bytes.toBytes("v"));
|
||||||
|
testCheckAndMutateWithFilterBuilder(put);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAndMutateWithFilterBuilderThenDelete() {
|
||||||
|
testCheckAndMutateWithFilterBuilder(new Delete(Bytes.toBytes(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAndMutateWithFilterBuilderThenMutations() throws IOException {
|
||||||
|
RowMutations mutations = new RowMutations(Bytes.toBytes(0))
|
||||||
|
.add(new Put(Bytes.toBytes(0))
|
||||||
|
.addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"), Bytes.toBytes("v")))
|
||||||
|
.add(new Delete(Bytes.toBytes(0)));
|
||||||
|
testCheckAndMutateWithFilterBuilder(mutations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMutateRow() throws IOException {
|
public void testMutateRow() throws IOException {
|
||||||
table.mutateRow(new RowMutations(Bytes.toBytes(0)).add(new Delete(Bytes.toBytes(0))));
|
table.mutateRow(new RowMutations(Bytes.toBytes(0)).add(new Delete(Bytes.toBytes(0))));
|
||||||
assertTrace("mutateRow");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testScanAll() throws IOException {
|
public void testScanAll() {
|
||||||
table.scanAll(new Scan().setCaching(1).setMaxResultSize(1).setLimit(1)).join();
|
table.scanAll(new Scan().setCaching(1).setMaxResultSize(1).setLimit(1)).join();
|
||||||
assertTrace("scanAll");
|
assertTrace("SCAN");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -331,13 +453,13 @@ public class TestAsyncTableTracing {
|
||||||
.allOf(
|
.allOf(
|
||||||
table.exists(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
table.exists(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||||
.join();
|
.join();
|
||||||
assertTrace("getList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExistsAll() {
|
public void testExistsAll() {
|
||||||
table.existsAll(Arrays.asList(new Get(Bytes.toBytes(0)))).join();
|
table.existsAll(Arrays.asList(new Get(Bytes.toBytes(0)))).join();
|
||||||
assertTrace("getList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -345,13 +467,13 @@ public class TestAsyncTableTracing {
|
||||||
CompletableFuture
|
CompletableFuture
|
||||||
.allOf(table.get(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
.allOf(table.get(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||||
.join();
|
.join();
|
||||||
assertTrace("getList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAll() {
|
public void testGetAll() {
|
||||||
table.getAll(Arrays.asList(new Get(Bytes.toBytes(0)))).join();
|
table.getAll(Arrays.asList(new Get(Bytes.toBytes(0)))).join();
|
||||||
assertTrace("getList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -360,14 +482,14 @@ public class TestAsyncTableTracing {
|
||||||
.allOf(table.put(Arrays.asList(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
|
.allOf(table.put(Arrays.asList(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
|
||||||
Bytes.toBytes("cq"), Bytes.toBytes("v")))).toArray(new CompletableFuture[0]))
|
Bytes.toBytes("cq"), Bytes.toBytes("v")))).toArray(new CompletableFuture[0]))
|
||||||
.join();
|
.join();
|
||||||
assertTrace("putList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPutAll() {
|
public void testPutAll() {
|
||||||
table.putAll(Arrays.asList(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
|
table.putAll(Arrays.asList(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
|
||||||
Bytes.toBytes("cq"), Bytes.toBytes("v")))).join();
|
Bytes.toBytes("cq"), Bytes.toBytes("v")))).join();
|
||||||
assertTrace("putList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -376,13 +498,13 @@ public class TestAsyncTableTracing {
|
||||||
.allOf(
|
.allOf(
|
||||||
table.delete(Arrays.asList(new Delete(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
table.delete(Arrays.asList(new Delete(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||||
.join();
|
.join();
|
||||||
assertTrace("deleteList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteAll() {
|
public void testDeleteAll() {
|
||||||
table.deleteAll(Arrays.asList(new Delete(Bytes.toBytes(0)))).join();
|
table.deleteAll(Arrays.asList(new Delete(Bytes.toBytes(0)))).join();
|
||||||
assertTrace("deleteList");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -391,13 +513,13 @@ public class TestAsyncTableTracing {
|
||||||
.allOf(
|
.allOf(
|
||||||
table.batch(Arrays.asList(new Delete(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
table.batch(Arrays.asList(new Delete(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||||
.join();
|
.join();
|
||||||
assertTrace("batch");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBatchAll() {
|
public void testBatchAll() {
|
||||||
table.batchAll(Arrays.asList(new Delete(Bytes.toBytes(0)))).join();
|
table.batchAll(Arrays.asList(new Delete(Bytes.toBytes(0)))).join();
|
||||||
assertTrace("batch");
|
assertTrace("BATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.client.trace.hamcrest;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.hasProperty;
|
||||||
|
import io.opentelemetry.api.common.AttributeKey;
|
||||||
|
import io.opentelemetry.api.common.Attributes;
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper methods for matching against instances of {@link io.opentelemetry.api.common.Attributes}.
|
||||||
|
*/
|
||||||
|
public final class AttributesMatchers {
|
||||||
|
|
||||||
|
private AttributesMatchers() { }
|
||||||
|
|
||||||
|
public static <T> Matcher<Attributes> containsEntry(
|
||||||
|
Matcher<AttributeKey<? super T>> keyMatcher,
|
||||||
|
Matcher<? super T> valueMatcher
|
||||||
|
) {
|
||||||
|
return new IsAttributesContaining<>(keyMatcher, valueMatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Matcher<Attributes> containsEntry(AttributeKey<T> key, T value) {
|
||||||
|
return containsEntry(equalTo(key), equalTo(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matcher<Attributes> containsEntry(String key, String value) {
|
||||||
|
return containsEntry(AttributeKey.stringKey(key), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class IsAttributesContaining<T> extends TypeSafeMatcher<Attributes> {
|
||||||
|
private final Matcher<AttributeKey<? super T>> keyMatcher;
|
||||||
|
private final Matcher<? super T> valueMatcher;
|
||||||
|
|
||||||
|
private IsAttributesContaining(
|
||||||
|
final Matcher<AttributeKey<? super T>> keyMatcher,
|
||||||
|
final Matcher<? super T> valueMatcher
|
||||||
|
) {
|
||||||
|
this.keyMatcher = keyMatcher;
|
||||||
|
this.valueMatcher = valueMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean matchesSafely(Attributes item) {
|
||||||
|
return item.asMap().entrySet().stream().anyMatch(e -> allOf(
|
||||||
|
hasProperty("key", keyMatcher),
|
||||||
|
hasProperty("value", valueMatcher))
|
||||||
|
.matches(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeMismatchSafely(Attributes item, Description mismatchDescription) {
|
||||||
|
mismatchDescription
|
||||||
|
.appendText("Attributes was ")
|
||||||
|
.appendValueList("[", ", ", "]", item.asMap().entrySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description
|
||||||
|
.appendText("Attributes containing [")
|
||||||
|
.appendDescriptionOf(keyMatcher)
|
||||||
|
.appendText("->")
|
||||||
|
.appendDescriptionOf(valueMatcher)
|
||||||
|
.appendText("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.client.trace.hamcrest;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import io.opentelemetry.api.common.Attributes;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.api.trace.StatusCode;
|
||||||
|
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||||
|
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.FeatureMatcher;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper methods for matching against instances of {@link SpanData}.
|
||||||
|
*/
|
||||||
|
public final class SpanDataMatchers {
|
||||||
|
|
||||||
|
private SpanDataMatchers() { }
|
||||||
|
|
||||||
|
public static Matcher<SpanData> hasAttributes(Matcher<Attributes> matcher) {
|
||||||
|
return new FeatureMatcher<SpanData, Attributes>(
|
||||||
|
matcher, "SpanData having attributes that ", "attributes"
|
||||||
|
) {
|
||||||
|
@Override protected Attributes featureValueOf(SpanData item) {
|
||||||
|
return item.getAttributes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matcher<SpanData> hasEnded() {
|
||||||
|
return new TypeSafeMatcher<SpanData>() {
|
||||||
|
@Override protected boolean matchesSafely(SpanData item) {
|
||||||
|
return item.hasEnded();
|
||||||
|
}
|
||||||
|
@Override public void describeTo(Description description) {
|
||||||
|
description.appendText("SpanData that hasEnded");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matcher<SpanData> hasKind(SpanKind kind) {
|
||||||
|
return new FeatureMatcher<SpanData, SpanKind>(
|
||||||
|
equalTo(kind), "SpanData with kind that", "SpanKind") {
|
||||||
|
@Override protected SpanKind featureValueOf(SpanData item) {
|
||||||
|
return item.getKind();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matcher<SpanData> hasName(String name) {
|
||||||
|
return hasName(equalTo(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matcher<SpanData> hasName(Matcher<String> matcher) {
|
||||||
|
return new FeatureMatcher<SpanData, String>(matcher, "SpanKind with a name that", "name") {
|
||||||
|
@Override protected String featureValueOf(SpanData item) {
|
||||||
|
return item.getName();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matcher<SpanData> hasStatusWithCode(StatusCode statusCode) {
|
||||||
|
final Matcher<StatusCode> matcher = is(equalTo(statusCode));
|
||||||
|
return new TypeSafeMatcher<SpanData>() {
|
||||||
|
@Override protected boolean matchesSafely(SpanData item) {
|
||||||
|
final StatusData statusData = item.getStatus();
|
||||||
|
return statusData != null
|
||||||
|
&& statusData.getStatusCode() != null
|
||||||
|
&& matcher.matches(statusData.getStatusCode());
|
||||||
|
}
|
||||||
|
@Override public void describeTo(Description description) {
|
||||||
|
description.appendText("SpanData with StatusCode that ").appendDescriptionOf(matcher);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,9 @@ import org.apache.yetus.audience.InterfaceAudience;
|
||||||
*/
|
*/
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public final class HBaseSemanticAttributes {
|
public final class HBaseSemanticAttributes {
|
||||||
|
public static final AttributeKey<String> DB_NAME = SemanticAttributes.DB_NAME;
|
||||||
public static final AttributeKey<String> NAMESPACE_KEY = SemanticAttributes.DB_HBASE_NAMESPACE;
|
public static final AttributeKey<String> NAMESPACE_KEY = SemanticAttributes.DB_HBASE_NAMESPACE;
|
||||||
|
public static final AttributeKey<String> DB_OPERATION = SemanticAttributes.DB_OPERATION;
|
||||||
public static final AttributeKey<String> TABLE_KEY = AttributeKey.stringKey("db.hbase.table");
|
public static final AttributeKey<String> TABLE_KEY = AttributeKey.stringKey("db.hbase.table");
|
||||||
public static final AttributeKey<List<String>> REGION_NAMES_KEY =
|
public static final AttributeKey<List<String>> REGION_NAMES_KEY =
|
||||||
AttributeKey.stringArrayKey("db.hbase.regions");
|
AttributeKey.stringArrayKey("db.hbase.regions");
|
||||||
|
@ -44,5 +46,23 @@ public final class HBaseSemanticAttributes {
|
||||||
AttributeKey.booleanKey("db.hbase.rowlock.readlock");
|
AttributeKey.booleanKey("db.hbase.rowlock.readlock");
|
||||||
public static final AttributeKey<String> WAL_IMPL = AttributeKey.stringKey("db.hbase.wal.impl");
|
public static final AttributeKey<String> WAL_IMPL = AttributeKey.stringKey("db.hbase.wal.impl");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are values used with {@link #DB_OPERATION}. They correspond with the implementations of
|
||||||
|
* {@code org.apache.hadoop.hbase.client.Operation}, as well as
|
||||||
|
* {@code org.apache.hadoop.hbase.client.CheckAndMutate}, and "MULTI", meaning a batch of multiple
|
||||||
|
* operations.
|
||||||
|
*/
|
||||||
|
public enum Operation {
|
||||||
|
APPEND,
|
||||||
|
BATCH,
|
||||||
|
CHECK_AND_MUTATE,
|
||||||
|
COPROC_EXEC,
|
||||||
|
DELETE,
|
||||||
|
GET,
|
||||||
|
INCREMENT,
|
||||||
|
PUT,
|
||||||
|
SCAN,
|
||||||
|
}
|
||||||
|
|
||||||
private HBaseSemanticAttributes() { }
|
private HBaseSemanticAttributes() { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,9 +91,11 @@ public final class TraceUtil {
|
||||||
/**
|
/**
|
||||||
* Trace an asynchronous operation for a table.
|
* Trace an asynchronous operation for a table.
|
||||||
*/
|
*/
|
||||||
public static <T> CompletableFuture<T> tracedFuture(Supplier<CompletableFuture<T>> action,
|
public static <T> CompletableFuture<T> tracedFuture(
|
||||||
String spanName, TableName tableName) {
|
Supplier<CompletableFuture<T>> action,
|
||||||
Span span = createTableSpan(spanName, tableName);
|
Supplier<Span> spanSupplier
|
||||||
|
) {
|
||||||
|
Span span = spanSupplier.get();
|
||||||
try (Scope scope = span.makeCurrent()) {
|
try (Scope scope = span.makeCurrent()) {
|
||||||
CompletableFuture<T> future = action.get();
|
CompletableFuture<T> future = action.get();
|
||||||
endSpan(future, span);
|
endSpan(future, span);
|
||||||
|
@ -119,8 +121,10 @@ public final class TraceUtil {
|
||||||
* {@code futures} are completed.
|
* {@code futures} are completed.
|
||||||
*/
|
*/
|
||||||
public static <T> List<CompletableFuture<T>> tracedFutures(
|
public static <T> List<CompletableFuture<T>> tracedFutures(
|
||||||
Supplier<List<CompletableFuture<T>>> action, String spanName, TableName tableName) {
|
Supplier<List<CompletableFuture<T>>> action,
|
||||||
Span span = createTableSpan(spanName, tableName);
|
Supplier<Span> spanSupplier
|
||||||
|
) {
|
||||||
|
Span span = spanSupplier.get();
|
||||||
try (Scope scope = span.makeCurrent()) {
|
try (Scope scope = span.makeCurrent()) {
|
||||||
List<CompletableFuture<T>> futures = action.get();
|
List<CompletableFuture<T>> futures = action.get();
|
||||||
endSpan(CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])), span);
|
endSpan(CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])), span);
|
||||||
|
|
Loading…
Reference in New Issue