|
|
@ -25,8 +25,10 @@ |
|
|
|
|
|
|
|
|
|
|
|
#include "absl/strings/cord.h" |
|
|
|
#include "absl/strings/cord.h" |
|
|
|
#include "absl/strings/escaping.h" |
|
|
|
#include "absl/strings/escaping.h" |
|
|
|
|
|
|
|
#include "absl/strings/match.h" |
|
|
|
#include "absl/strings/str_format.h" |
|
|
|
#include "absl/strings/str_format.h" |
|
|
|
#include "absl/strings/str_join.h" |
|
|
|
#include "absl/strings/str_join.h" |
|
|
|
|
|
|
|
#include "absl/time/clock.h" |
|
|
|
|
|
|
|
|
|
|
|
#include "google/protobuf/any.upb.h" |
|
|
|
#include "google/protobuf/any.upb.h" |
|
|
|
#include "google/rpc/status.upb.h" |
|
|
|
#include "google/rpc/status.upb.h" |
|
|
@ -37,42 +39,50 @@ namespace grpc_core { |
|
|
|
namespace { |
|
|
|
namespace { |
|
|
|
|
|
|
|
|
|
|
|
#define TYPE_URL_PREFIX "type.googleapis.com/grpc.status." |
|
|
|
#define TYPE_URL_PREFIX "type.googleapis.com/grpc.status." |
|
|
|
|
|
|
|
#define TYPE_INT_TAG "int." |
|
|
|
|
|
|
|
#define TYPE_STR_TAG "str." |
|
|
|
|
|
|
|
#define TYPE_TIME_TAG "time." |
|
|
|
|
|
|
|
#define TYPE_CHILDREN_TAG "children" |
|
|
|
#define TYPE_URL(name) (TYPE_URL_PREFIX name) |
|
|
|
#define TYPE_URL(name) (TYPE_URL_PREFIX name) |
|
|
|
const absl::string_view kTypeUrlPrefix = TYPE_URL_PREFIX; |
|
|
|
const absl::string_view kTypeUrlPrefix = TYPE_URL_PREFIX; |
|
|
|
const absl::string_view kChildrenPropertyUrl = TYPE_URL("children"); |
|
|
|
const absl::string_view kTypeIntTag = TYPE_INT_TAG; |
|
|
|
|
|
|
|
const absl::string_view kTypeStrTag = TYPE_STR_TAG; |
|
|
|
|
|
|
|
const absl::string_view kTypeTimeTag = TYPE_TIME_TAG; |
|
|
|
|
|
|
|
const absl::string_view kTypeChildrenTag = TYPE_CHILDREN_TAG; |
|
|
|
|
|
|
|
const absl::string_view kChildrenPropertyUrl = TYPE_URL(TYPE_CHILDREN_TAG); |
|
|
|
|
|
|
|
|
|
|
|
const char* GetStatusIntPropertyUrl(StatusIntProperty key) { |
|
|
|
const char* GetStatusIntPropertyUrl(StatusIntProperty key) { |
|
|
|
switch (key) { |
|
|
|
switch (key) { |
|
|
|
case StatusIntProperty::kErrorNo: |
|
|
|
case StatusIntProperty::kErrorNo: |
|
|
|
return TYPE_URL("errno"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "errno"); |
|
|
|
case StatusIntProperty::kFileLine: |
|
|
|
case StatusIntProperty::kFileLine: |
|
|
|
return TYPE_URL("file_line"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "file_line"); |
|
|
|
case StatusIntProperty::kStreamId: |
|
|
|
case StatusIntProperty::kStreamId: |
|
|
|
return TYPE_URL("stream_id"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "stream_id"); |
|
|
|
case StatusIntProperty::kRpcStatus: |
|
|
|
case StatusIntProperty::kRpcStatus: |
|
|
|
return TYPE_URL("grpc_status"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "grpc_status"); |
|
|
|
case StatusIntProperty::kOffset: |
|
|
|
case StatusIntProperty::kOffset: |
|
|
|
return TYPE_URL("offset"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "offset"); |
|
|
|
case StatusIntProperty::kIndex: |
|
|
|
case StatusIntProperty::kIndex: |
|
|
|
return TYPE_URL("index"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "index"); |
|
|
|
case StatusIntProperty::kSize: |
|
|
|
case StatusIntProperty::kSize: |
|
|
|
return TYPE_URL("size"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "size"); |
|
|
|
case StatusIntProperty::kHttp2Error: |
|
|
|
case StatusIntProperty::kHttp2Error: |
|
|
|
return TYPE_URL("http2_error"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "http2_error"); |
|
|
|
case StatusIntProperty::kTsiCode: |
|
|
|
case StatusIntProperty::kTsiCode: |
|
|
|
return TYPE_URL("tsi_code"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "tsi_code"); |
|
|
|
case StatusIntProperty::kWsaError: |
|
|
|
case StatusIntProperty::kWsaError: |
|
|
|
return TYPE_URL("wsa_error"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "wsa_error"); |
|
|
|
case StatusIntProperty::kFd: |
|
|
|
case StatusIntProperty::kFd: |
|
|
|
return TYPE_URL("fd"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "fd"); |
|
|
|
case StatusIntProperty::kHttpStatus: |
|
|
|
case StatusIntProperty::kHttpStatus: |
|
|
|
return TYPE_URL("http_status"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "http_status"); |
|
|
|
case StatusIntProperty::kOccurredDuringWrite: |
|
|
|
case StatusIntProperty::kOccurredDuringWrite: |
|
|
|
return TYPE_URL("occurred_during_write"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "occurred_during_write"); |
|
|
|
case StatusIntProperty::ChannelConnectivityState: |
|
|
|
case StatusIntProperty::ChannelConnectivityState: |
|
|
|
return TYPE_URL("channel_connectivity_state"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "channel_connectivity_state"); |
|
|
|
case StatusIntProperty::kLbPolicyDrop: |
|
|
|
case StatusIntProperty::kLbPolicyDrop: |
|
|
|
return TYPE_URL("lb_policy_drop"); |
|
|
|
return TYPE_URL(TYPE_INT_TAG "lb_policy_drop"); |
|
|
|
} |
|
|
|
} |
|
|
|
GPR_UNREACHABLE_CODE(return "unknown"); |
|
|
|
GPR_UNREACHABLE_CODE(return "unknown"); |
|
|
|
} |
|
|
|
} |
|
|
@ -80,29 +90,35 @@ const char* GetStatusIntPropertyUrl(StatusIntProperty key) { |
|
|
|
const char* GetStatusStrPropertyUrl(StatusStrProperty key) { |
|
|
|
const char* GetStatusStrPropertyUrl(StatusStrProperty key) { |
|
|
|
switch (key) { |
|
|
|
switch (key) { |
|
|
|
case StatusStrProperty::kDescription: |
|
|
|
case StatusStrProperty::kDescription: |
|
|
|
return TYPE_URL("description"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "description"); |
|
|
|
case StatusStrProperty::kFile: |
|
|
|
case StatusStrProperty::kFile: |
|
|
|
return TYPE_URL("file"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "file"); |
|
|
|
case StatusStrProperty::kOsError: |
|
|
|
case StatusStrProperty::kOsError: |
|
|
|
return TYPE_URL("os_error"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "os_error"); |
|
|
|
case StatusStrProperty::kSyscall: |
|
|
|
case StatusStrProperty::kSyscall: |
|
|
|
return TYPE_URL("syscall"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "syscall"); |
|
|
|
case StatusStrProperty::kTargetAddress: |
|
|
|
case StatusStrProperty::kTargetAddress: |
|
|
|
return TYPE_URL("target_address"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "target_address"); |
|
|
|
case StatusStrProperty::kGrpcMessage: |
|
|
|
case StatusStrProperty::kGrpcMessage: |
|
|
|
return TYPE_URL("grpc_message"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "grpc_message"); |
|
|
|
case StatusStrProperty::kRawBytes: |
|
|
|
case StatusStrProperty::kRawBytes: |
|
|
|
return TYPE_URL("raw_bytes"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "raw_bytes"); |
|
|
|
case StatusStrProperty::kTsiError: |
|
|
|
case StatusStrProperty::kTsiError: |
|
|
|
return TYPE_URL("tsi_error"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "tsi_error"); |
|
|
|
case StatusStrProperty::kFilename: |
|
|
|
case StatusStrProperty::kFilename: |
|
|
|
return TYPE_URL("filename"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "filename"); |
|
|
|
case StatusStrProperty::kKey: |
|
|
|
case StatusStrProperty::kKey: |
|
|
|
return TYPE_URL("key"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "key"); |
|
|
|
case StatusStrProperty::kValue: |
|
|
|
case StatusStrProperty::kValue: |
|
|
|
return TYPE_URL("value"); |
|
|
|
return TYPE_URL(TYPE_STR_TAG "value"); |
|
|
|
case StatusStrProperty::kCreatedTime: |
|
|
|
} |
|
|
|
return TYPE_URL("created_time"); |
|
|
|
GPR_UNREACHABLE_CODE(return "unknown"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* GetStatusTimePropertyUrl(StatusTimeProperty key) { |
|
|
|
|
|
|
|
switch (key) { |
|
|
|
|
|
|
|
case StatusTimeProperty::kCreated: |
|
|
|
|
|
|
|
return TYPE_URL(TYPE_TIME_TAG "created_time"); |
|
|
|
} |
|
|
|
} |
|
|
|
GPR_UNREACHABLE_CODE(return "unknown"); |
|
|
|
GPR_UNREACHABLE_CODE(return "unknown"); |
|
|
|
} |
|
|
|
} |
|
|
@ -150,8 +166,7 @@ absl::Status StatusCreate(absl::StatusCode code, absl::string_view msg, |
|
|
|
if (location.line() != -1) { |
|
|
|
if (location.line() != -1) { |
|
|
|
StatusSetInt(&s, StatusIntProperty::kFileLine, location.line()); |
|
|
|
StatusSetInt(&s, StatusIntProperty::kFileLine, location.line()); |
|
|
|
} |
|
|
|
} |
|
|
|
absl::Time now = grpc_core::ToAbslTime(gpr_now(GPR_CLOCK_REALTIME)); |
|
|
|
StatusSetTime(&s, StatusTimeProperty::kCreated, absl::Now()); |
|
|
|
StatusSetStr(&s, StatusStrProperty::kCreatedTime, absl::FormatTime(now)); |
|
|
|
|
|
|
|
for (const absl::Status& child : children) { |
|
|
|
for (const absl::Status& child : children) { |
|
|
|
if (!child.ok()) { |
|
|
|
if (!child.ok()) { |
|
|
|
StatusAddChild(&s, child); |
|
|
|
StatusAddChild(&s, child); |
|
|
@ -200,6 +215,29 @@ absl::optional<std::string> StatusGetStr(const absl::Status& status, |
|
|
|
return {}; |
|
|
|
return {}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void StatusSetTime(absl::Status* status, StatusTimeProperty key, |
|
|
|
|
|
|
|
absl::Time time) { |
|
|
|
|
|
|
|
status->SetPayload(GetStatusTimePropertyUrl(key), |
|
|
|
|
|
|
|
absl::Cord(absl::string_view( |
|
|
|
|
|
|
|
reinterpret_cast<const char*>(&time), sizeof(time)))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
absl::optional<absl::Time> StatusGetTime(const absl::Status& status, |
|
|
|
|
|
|
|
StatusTimeProperty key) { |
|
|
|
|
|
|
|
absl::optional<absl::Cord> p = |
|
|
|
|
|
|
|
status.GetPayload(GetStatusTimePropertyUrl(key)); |
|
|
|
|
|
|
|
if (p.has_value()) { |
|
|
|
|
|
|
|
absl::optional<absl::string_view> sv = p->TryFlat(); |
|
|
|
|
|
|
|
if (sv.has_value()) { |
|
|
|
|
|
|
|
return *reinterpret_cast<const absl::Time*>(sv->data()); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
std::string s = std::string(*p); |
|
|
|
|
|
|
|
return *reinterpret_cast<const absl::Time*>(s.c_str()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return {}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void StatusAddChild(absl::Status* status, absl::Status child) { |
|
|
|
void StatusAddChild(absl::Status* status, absl::Status child) { |
|
|
|
upb::Arena arena; |
|
|
|
upb::Arena arena; |
|
|
|
// Serialize msg to buf
|
|
|
|
// Serialize msg to buf
|
|
|
@ -237,20 +275,45 @@ std::string StatusToString(const absl::Status& status) { |
|
|
|
} |
|
|
|
} |
|
|
|
std::vector<std::string> kvs; |
|
|
|
std::vector<std::string> kvs; |
|
|
|
absl::optional<absl::Cord> children; |
|
|
|
absl::optional<absl::Cord> children; |
|
|
|
status.ForEachPayload( |
|
|
|
status.ForEachPayload([&](absl::string_view type_url, |
|
|
|
[&](absl::string_view type_url, const absl::Cord& payload) { |
|
|
|
const absl::Cord& payload) { |
|
|
|
if (type_url.substr(0, kTypeUrlPrefix.size()) == kTypeUrlPrefix) { |
|
|
|
if (absl::StartsWith(type_url, kTypeUrlPrefix)) { |
|
|
|
type_url.remove_prefix(kTypeUrlPrefix.size()); |
|
|
|
type_url.remove_prefix(kTypeUrlPrefix.size()); |
|
|
|
} |
|
|
|
if (type_url == kTypeChildrenTag) { |
|
|
|
if (type_url == kChildrenPropertyUrl.substr(kTypeUrlPrefix.size())) { |
|
|
|
children = payload; |
|
|
|
children = payload; |
|
|
|
return; |
|
|
|
} else { |
|
|
|
} |
|
|
|
absl::optional<absl::string_view> payload_view = payload.TryFlat(); |
|
|
|
absl::string_view payload_view; |
|
|
|
std::string payload_str = absl::CHexEscape( |
|
|
|
std::string payload_storage; |
|
|
|
payload_view.has_value() ? *payload_view : std::string(payload)); |
|
|
|
if (payload.TryFlat().has_value()) { |
|
|
|
kvs.push_back(absl::StrCat(type_url, ":\"", payload_str, "\"")); |
|
|
|
payload_view = payload.TryFlat().value(); |
|
|
|
} |
|
|
|
} else { |
|
|
|
}); |
|
|
|
payload_storage = std::string(payload); |
|
|
|
|
|
|
|
payload_view = payload_storage; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (absl::StartsWith(type_url, kTypeIntTag)) { |
|
|
|
|
|
|
|
type_url.remove_prefix(kTypeIntTag.size()); |
|
|
|
|
|
|
|
kvs.push_back(absl::StrCat(type_url, ":", payload_view)); |
|
|
|
|
|
|
|
} else if (absl::StartsWith(type_url, kTypeStrTag)) { |
|
|
|
|
|
|
|
type_url.remove_prefix(kTypeStrTag.size()); |
|
|
|
|
|
|
|
kvs.push_back(absl::StrCat(type_url, ":\"", |
|
|
|
|
|
|
|
absl::CHexEscape(payload_view), "\"")); |
|
|
|
|
|
|
|
} else if (absl::StartsWith(type_url, kTypeTimeTag)) { |
|
|
|
|
|
|
|
type_url.remove_prefix(kTypeTimeTag.size()); |
|
|
|
|
|
|
|
absl::Time t = |
|
|
|
|
|
|
|
*reinterpret_cast<const absl::Time*>(payload_view.data()); |
|
|
|
|
|
|
|
kvs.push_back(absl::StrCat(type_url, ":\"", absl::FormatTime(t), "\"")); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
kvs.push_back(absl::StrCat(type_url, ":\"", |
|
|
|
|
|
|
|
absl::CHexEscape(payload_view), "\"")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
absl::optional<absl::string_view> payload_view = payload.TryFlat(); |
|
|
|
|
|
|
|
std::string payload_str = absl::CHexEscape( |
|
|
|
|
|
|
|
payload_view.has_value() ? *payload_view : std::string(payload)); |
|
|
|
|
|
|
|
kvs.push_back(absl::StrCat(type_url, ":\"", payload_str, "\"")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
if (children.has_value()) { |
|
|
|
if (children.has_value()) { |
|
|
|
std::vector<absl::Status> children_status = ParseChildren(*children); |
|
|
|
std::vector<absl::Status> children_status = ParseChildren(*children); |
|
|
|
std::vector<std::string> children_text; |
|
|
|
std::vector<std::string> children_text; |
|
|
|