diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/DriverConnectionHandler.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/DriverConnectionHandler.java index 1ae9f9a1..ad9df5cf 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/DriverConnectionHandler.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/DriverConnectionHandler.java @@ -29,6 +29,7 @@ import com.datastax.oss.protocol.internal.request.Batch; import com.datastax.oss.protocol.internal.request.Execute; import com.datastax.oss.protocol.internal.request.Query; +import com.datastax.oss.protocol.internal.response.Error; import com.google.api.gax.grpc.GrpcCallContext; import com.google.api.gax.rpc.ApiCallContext; import com.google.cloud.spanner.adapter.metrics.BuiltInMetricsRecorder; @@ -66,6 +67,8 @@ final class DriverConnectionHandler implements Runnable { private static final ByteBufAllocator byteBufAllocator = ByteBufAllocator.DEFAULT; private static final FrameCodec serverFrameCodec = FrameCodec.defaultServer(new ByteBufPrimitiveCodec(byteBufAllocator), Compressor.none()); + private static final FrameCodec clientFrameCodec = + FrameCodec.defaultClient(new ByteBufPrimitiveCodec(byteBufAllocator), Compressor.none()); private final Socket socket; private final AdapterClientWrapper adapterClientWrapper; private final Optional maxCommitDelayMillis; @@ -79,6 +82,12 @@ final class DriverConnectionHandler implements Runnable { private static final GrpcCallContext DEFAULT_CONTEXT_WITH_LAR = GrpcCallContext.createDefault().withExtraHeaders(ROUTE_TO_LEADER_HEADER_MAP); private static final byte[] EMPTY_BYTES = new byte[0]; + private static final String ENV_VAR_GOOGLE_SPANNER_CASSANDRA_LOG_SERVER_ERRORS = + "GOOGLE_SPANNER_CASSANDRA_LOG_SERVER_ERRORS"; + private static final boolean LOG_SERVER_ERRORS = + Boolean.parseBoolean( + System.getenv() + .getOrDefault(ENV_VAR_GOOGLE_SPANNER_CASSANDRA_LOG_SERVER_ERRORS, "false")); /** * Constructor for DriverConnectionHandler. @@ -164,7 +173,13 @@ private void processRequestsLoop(InputStream inputStream, OutputStream outputStr prepareResult.getAttachments(), prepareResult.getContext(), streamId); - // Now response holds the gRPC result, which might still be empty. + if (LOG_SERVER_ERRORS) { + Frame frame = decodeClientFrame(response.toByteArray()); + if (frame.message instanceof Error) { + Error error = (Error) frame.message; + LOG.info("ERROR: code: {}, message: {}", error.code, error.message); + } + } } } catch (RuntimeException e) { // 5. Handle any error during payload construction or attachment processing. @@ -288,6 +303,13 @@ private Frame decodeFrame(byte[] payload) { return frame; } + private Frame decodeClientFrame(byte[] payload) { + ByteBuf payloadBuf = Unpooled.wrappedBuffer(payload); + Frame frame = clientFrameCodec.decode(payloadBuf); + payloadBuf.release(); + return frame; + } + /** * Attempts to prepare the given payload prior to sending the request. *