下面列出了io.grpc.Status#getCause ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Determine whether the given status maps to the error that GRPC-Java throws when an Android
* device is missing required SSL Ciphers.
*
* <p>This error is non-recoverable and must be addressed by the app developer.
*/
public static boolean isMissingSslCiphers(Status status) {
Status.Code code = status.getCode();
Throwable t = status.getCause();
// Check for the presence of a cipher error in the event of an SSLHandshakeException. This is
// the special case of SSLHandshakeException that contains the cipher error.
boolean hasCipherError = false;
if (t instanceof SSLHandshakeException && t.getMessage().contains("no ciphers available")) {
hasCipherError = true;
}
return Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP
&& code.equals(Status.Code.UNAVAILABLE)
&& hasCipherError;
}
static HttpHeaders statusToTrailers(
ServiceRequestContext ctx, Status status, Metadata metadata, boolean headersSent) {
final HttpHeadersBuilder trailers = GrpcTrailersUtil.statusToTrailers(
status.getCode().value(), status.getDescription(), headersSent);
MetadataUtil.fillHeaders(metadata, trailers);
if (ctx.config().verboseResponses() && status.getCause() != null) {
final ThrowableProto proto = GrpcStatus.serializeThrowable(status.getCause());
trailers.add(GrpcHeaderNames.ARMERIA_GRPC_THROWABLEPROTO_BIN,
Base64.getEncoder().encodeToString(proto.toByteArray()));
}
final HttpHeaders additionalTrailers = ctx.additionalResponseTrailers();
ctx.mutateAdditionalResponseTrailers(HttpHeadersBuilder::clear);
trailers.add(additionalTrailers);
return trailers.build();
}
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
ServerCall<ReqT, RespT> wrappedCall = new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {
@Override
public void sendMessage(RespT message) {
super.sendMessage(message);
}
@Override
public void close(Status status, Metadata trailers) {
Throwable exception;
Status newStatus;
if (
status.getCode() == Status.Code.UNKNOWN
&& status.getDescription() == null
&& (exception = status.getCause()) != null
&& (newStatus = statusForException(exception)) != null
) {
status = newStatus
.withCause(exception)
.withDescription(stacktraceToString(exception));
}
super.close(status, trailers);
}
};
return next.startCall(wrappedCall, headers);
}
private FirebaseFirestoreException exceptionFromStatus(Status status) {
if (Datastore.isMissingSslCiphers(status)) {
return new FirebaseFirestoreException(
Datastore.SSL_DEPENDENCY_ERROR_MESSAGE,
Code.fromValue(status.getCode().value()),
status.getCause());
}
return Util.exceptionFromStatus(status);
}
/** Converts io.grpc.Status to com.google.rpc.Status proto for logging. */
private static com.google.rpc.Status makeStatusProto(Status status) {
String message = "";
if (status.getCause() != null) {
message = status.getCause().toString();
} else if (status.getDescription() != null) {
message = status.getDescription();
}
return com.google.rpc.Status.newBuilder()
.setCode(status.getCode().value())
.setMessage(message)
.build();
}
/**
* Override to change what data from the status or trailers are parsed into the span modeling it.
*
* <p><em>Note</em>: {@link Status#getCause()} will be set as {@link Span#error(Throwable)} by
* default. You don't need to parse it here.
*/
protected void onClose(Status status, Metadata trailers, SpanCustomizer span) {
if (status == null || status.isOk()) return;
String code = String.valueOf(status.getCode());
span.tag("grpc.status_code", code);
if (status.getCause() == null) span.tag("error", code);
}
/**
* Closes the stream and cleans up as necessary:
*
* <ul>
* <li>closes the underlying GRPC stream;
* <li>calls the onClose handler with the given 'status';
* <li>sets internal stream state to 'finalState';
* <li>adjusts the backoff timer based on status
* </ul>
*
* <p>A new stream can be opened by calling {@link #start).
*
* @param finalState the intended state of the stream after closing.
* @param status the status to emit to the listener.
*/
private void close(State finalState, Status status) {
hardAssert(isStarted(), "Only started streams should be closed.");
hardAssert(
finalState == State.Error || status.equals(Status.OK),
"Can't provide an error when not in an error state.");
workerQueue.verifyIsCurrentThread();
if (Datastore.isMissingSslCiphers(status)) {
// The Android device is missing required SSL Ciphers. This error is non-recoverable and must
// be addressed by the app developer (see https://bit.ly/2XFpdma).
Util.crashMainThread(
new IllegalStateException(SSL_DEPENDENCY_ERROR_MESSAGE, status.getCause()));
}
// Cancel any outstanding timers (they're guaranteed not to execute).
cancelIdleCheck();
this.backoff.cancel();
// Invalidates any stream-related callbacks (e.g. from auth or the underlying stream),
// guaranteeing they won't execute.
this.closeCount++;
Code code = status.getCode();
if (code == Code.OK) {
// If this is an intentional close ensure we don't delay our next connection attempt.
backoff.reset();
} else if (code == Code.RESOURCE_EXHAUSTED) {
Logger.debug(
getClass().getSimpleName(),
"(%x) Using maximum backoff delay to prevent overloading the backend.",
System.identityHashCode(this));
backoff.resetToMax();
} else if (code == Code.UNAUTHENTICATED) {
// "unauthenticated" error means the token was rejected. Try force refreshing it in case it
// just expired.
firestoreChannel.invalidateToken();
} else if (code == Code.UNAVAILABLE) {
// This exception is thrown when the gRPC connection fails on the client side, To shorten
// reconnect time, we can use a shorter max delay when reconnecting.
if (status.getCause() instanceof java.net.UnknownHostException
|| status.getCause() instanceof java.net.ConnectException) {
backoff.setTemporaryMaxDelay(BACKOFF_CLIENT_NETWORK_FAILURE_MAX_DELAY_MS);
}
}
if (finalState != State.Error) {
Logger.debug(
getClass().getSimpleName(),
"(%x) Performing stream teardown",
System.identityHashCode(this));
tearDown();
}
if (call != null) {
// Clean up the underlying RPC. If this close() is in response to an error, don't attempt to
// call half-close to avoid secondary failures.
if (status.isOk()) {
Logger.debug(
getClass().getSimpleName(),
"(%x) Closing stream client-side",
System.identityHashCode(this));
call.halfClose();
}
call = null;
}
// This state must be assigned before calling listener.onClose to allow the callback to
// inhibit backoff or otherwise manipulate the state in its non-started state.
this.state = finalState;
// Notify the listener that the stream closed.
listener.onClose(status);
}
private String formatStatus(Status status) {
return "{code=" + status.getCode()
+ ", description=" + status.getDescription()
+ ", error=" + (status.getCause() == null ? "N/A" : status.getCause().getMessage())
+ '}';
}
private String formatStatus(Status status) {
return "{code=" + status.getCode()
+ ", description=" + status.getDescription()
+ ", error=" + (status.getCause() == null ? "N/A" : status.getCause().getMessage())
+ '}';
}
@Override
public void close(Status status, Metadata trailers) {
final AbstractSpan span = ContextManager.createLocalSpan(operationPrefix + RESPONSE_ON_CLOSE_OPERATION_NAME);
span.setComponent(ComponentsDefine.GRPC);
span.setLayer(SpanLayer.RPC_FRAMEWORK);
ContextManager.continued(contextSnapshot);
switch (status.getCode()) {
case OK:
break;
// UNKNOWN/INTERNAL status code will case error in this span.
// Those status code means some unexpected error occurred in server.
// Similar to 5XX in HTTP status.
case UNKNOWN:
case INTERNAL:
if (status.getCause() == null) {
span.errorOccurred().log(status.asRuntimeException());
} else {
span.errorOccurred().log(status.getCause());
}
break;
// Other status code means some predictable error occurred in server.
// Like PERMISSION_DENIED or UNAUTHENTICATED somethings.
// Similar to 4XX in HTTP status.
default:
// But if the status still has cause exception, we will log it too.
if (status.getCause() != null) {
span.errorOccurred().log(status.getCause());
}
break;
}
Tags.STATUS_CODE.set(span, status.getCode().name());
try {
super.close(status, trailers);
} catch (Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
throw t;
} finally {
ContextManager.stopSpan();
}
}