diff --git a/ledger/error/BUILD.bazel b/ledger/error/BUILD.bazel index 69a290de6e..ae7bd12253 100644 --- a/ledger/error/BUILD.bazel +++ b/ledger/error/BUILD.bazel @@ -49,6 +49,8 @@ da_scala_library( deps = [ ":error", "//libs-scala/contextualized-logging", + "@maven//:com_google_api_grpc_proto_google_common_protos", + "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", "@maven//:org_slf4j_slf4j_api", ], diff --git a/ledger/error/src/main/scala/com/daml/error/BaseError.scala b/ledger/error/src/main/scala/com/daml/error/BaseError.scala index 8fc254fa61..1a60528ead 100644 --- a/ledger/error/src/main/scala/com/daml/error/BaseError.scala +++ b/ledger/error/src/main/scala/com/daml/error/BaseError.scala @@ -3,6 +3,7 @@ package com.daml.error +import com.google.rpc.Status import io.grpc.StatusRuntimeException /** The main error interface for everything that should be logged and notified. @@ -50,6 +51,11 @@ trait BaseError extends LocationMixin { ): Unit = errorCodeLoggingContext.logError(this, extra) + def asGrpcStatusFromContext(implicit + errorCodeLoggingContext: ErrorCodeLoggingContext + ): Status = + code.asGrpcStatus(this) + def asGrpcErrorFromContext(implicit errorCodeLoggingContext: ErrorCodeLoggingContext ): StatusRuntimeException = @@ -88,7 +94,7 @@ object BaseError { val SecuritySensitiveMessageOnApi = "An error occurred. Please contact the operator and inquire about the request" - def extractContext[D](obj: D): Map[String, String] = { + def extractContext[D](obj: D): Map[String, String] = obj.getClass.getDeclaredFields .filterNot(x => ignoreFields.contains(x.getName) || x.getName.startsWith("_")) .map { field => @@ -96,7 +102,6 @@ object BaseError { (field.getName, field.get(obj).toString) } .toMap - } abstract class Impl( override val cause: String, @@ -116,9 +121,11 @@ object BaseError { def log(): Unit = logWithContext()(loggingContext) - def asGrpcError: StatusRuntimeException = { + def asGrpcStatus: Status = + code.asGrpcStatus(this)(loggingContext) + + def asGrpcError: StatusRuntimeException = code.asGrpcError(this)(loggingContext) - } // Automatically log the error on generation if (logOnCreation) { diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala b/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala index 45a6289c0a..400f986da7 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorCode.scala @@ -4,6 +4,7 @@ package com.daml.error import com.daml.error.ErrorCode.{ValidMetadataKeyRegex, truncateResourceForTransport} +import com.google.rpc.Status import io.grpc.Status.Code import io.grpc.StatusRuntimeException import io.grpc.protobuf.StatusProto @@ -58,9 +59,9 @@ abstract class ErrorCode(val id: String, val category: ErrorCategory)(implicit def toMsg(cause: => String, correlationId: Option[String]): String = s"${codeStr(correlationId)}: ${ErrorCode.truncateCause(cause)}" - def asGrpcError(err: BaseError)(implicit + def asGrpcStatus(err: BaseError)(implicit loggingContext: ErrorCodeLoggingContext - ): StatusRuntimeException = { + ): Status = { val ErrorCode.StatusInfo(codeGrpc, message, contextMap, correlationId) = getStatusInfo(err) @@ -126,9 +127,15 @@ abstract class ErrorCode(val id: String, val category: ErrorCategory)(implicit .foldLeft(statusBuilder) { case (acc, item) => acc.addDetails(item) } + statusBuilder.build() + } + def asGrpcError(err: BaseError)(implicit + loggingContext: ErrorCodeLoggingContext + ): StatusRuntimeException = { + val status = asGrpcStatus(err) // Builder methods for metadata are not exposed, so going route via creating an exception - val ex = StatusProto.toStatusRuntimeException(statusBuilder.build()) + val ex = StatusProto.toStatusRuntimeException(status) // Strip stack trace from exception new ErrorCode.ApiException(ex.getStatus, ex.getTrailers) }