sql_utils/common/status_payload_utils.cc (106 lines of code) (raw):
/*
* Copyright 2023 Google LLC
*
* Licensed 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.
*/
#include "sql_utils/common/status_payload_utils.h"
#include <string>
#include "google/protobuf/descriptor_database.h"
#include "google/protobuf/message.h"
#include "absl/memory/memory.h"
#include "absl/strings/cord.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/strip.h"
#include "sql_utils/base/status.h"
#include "sql_utils/base/status_payload.h"
namespace bigquery_ml_utils {
namespace internal {
// Whether the given status has any payload at all. The payloads themselves
// may be empty.
bool HasPayload(const absl::Status& status) {
return GetPayloadCount(status) > 0;
}
// Get the number of items within the payload.
int GetPayloadCount(const absl::Status& status) {
// Status interface forces scan for counting.
int count = 0;
status.ForEachPayload(
[&count](absl::string_view, const absl::Cord&) { ++count; });
return count;
}
std::string PayloadToString(absl::string_view type_url,
const absl::Cord& payload) {
absl::string_view descriptor_full_name = type_url;
if (absl::ConsumePrefix(&descriptor_full_name,
bigquery_ml_utils_base::kSqlTypeUrlPrefix)) {
const google::protobuf::DescriptorPool* pool =
google::protobuf::DescriptorPool::generated_pool();
const google::protobuf::Descriptor* desc =
pool->FindMessageTypeByName(std::string(descriptor_full_name));
if (desc != nullptr) {
google::protobuf::MessageFactory* factory =
google::protobuf::MessageFactory::generated_factory();
auto msg = absl::WrapUnique(factory->GetPrototype(desc)->New());
if (msg->ParseFromString(std::string(payload))) {
return absl::StrCat("[", descriptor_full_name, "] { ",
msg->ShortDebugString(), " }");
}
}
}
return absl::StrCat("[", type_url, "] <unknown type>");
}
// StatusCodeToString does not guarantee any format, this guarantees
// lower-case camel case (except OK, which is just "OK"). Invalid codes
// will be printed as an integer.
std::string LegacyStatusCodeToString(absl::StatusCode code) {
switch (code) {
case absl::StatusCode::kOk:
return "OK";
case absl::StatusCode::kCancelled:
return "generic::cancelled";
case absl::StatusCode::kUnknown:
return "generic::unknown";
case absl::StatusCode::kInvalidArgument:
return "generic::invalid_argument";
case absl::StatusCode::kDeadlineExceeded:
return "generic::deadline_exceeded";
case absl::StatusCode::kNotFound:
return "generic::not_found";
case absl::StatusCode::kAlreadyExists:
return "generic::already_exists";
case absl::StatusCode::kPermissionDenied:
return "generic::permission_denied";
case absl::StatusCode::kUnauthenticated:
return "generic::unauthenticated";
case absl::StatusCode::kResourceExhausted:
return "generic::resource_exhausted";
case absl::StatusCode::kFailedPrecondition:
return "generic::failed_precondition";
case absl::StatusCode::kAborted:
return "generic::aborted";
case absl::StatusCode::kOutOfRange:
return "generic::out_of_range";
case absl::StatusCode::kUnimplemented:
return "generic::unimplemented";
case absl::StatusCode::kInternal:
return "generic::internal";
case absl::StatusCode::kUnavailable:
return "generic::unavailable";
case absl::StatusCode::kDataLoss:
return "generic::data_loss";
default:
return absl::StrCat(code);
}
}
std::string PayloadToString(const absl::Status& status) {
std::string ret;
// Make our own version of absl::Join
bool prepend_space = false;
status.ForEachPayload([&ret, &prepend_space](absl::string_view type_url,
const absl::Cord& payload) {
absl::StrAppend(&ret, prepend_space ? " " : "",
PayloadToString(type_url, payload));
prepend_space = true;
});
return ret;
}
// Creates a human readable string from the status, including its payload.
// Exact form is not defined.
std::string StatusToString(const absl::Status& status) {
if (status.ok()) {
return "OK";
}
std::string ret = absl::StrCat(LegacyStatusCodeToString(status.code()), ": ",
status.message());
if (HasPayload(status)) {
absl::StrAppend(&ret, " ", PayloadToString(status));
}
return ret;
}
} // namespace internal
} // namespace bigquery_ml_utils