#include <grpc/support/port_platform.h>
#include "src/core/lib/channel/channel_trace.h"
#include <algorithm>
#include <utility>
#include "absl/strings/str_cat.h"
#include <grpc/support/alloc.h>
#include <grpc/support/json.h>
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/slice/slice_internal.h"
namespace grpc_core {
namespace channelz {
ChannelTrace::TraceEvent::TraceEvent(Severity severity, const grpc_slice& data,
RefCountedPtr<BaseNode> referenced_entity)
: severity_(severity),
data_(data),
timestamp_(Timestamp::Now().as_timespec(GPR_CLOCK_REALTIME)),
next_(nullptr),
referenced_entity_(std::move(referenced_entity)),
memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {}
ChannelTrace::TraceEvent::TraceEvent(Severity severity, const grpc_slice& data)
: severity_(severity),
data_(data),
timestamp_(Timestamp::Now().as_timespec(GPR_CLOCK_REALTIME)),
next_(nullptr),
memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {}
ChannelTrace::TraceEvent::~TraceEvent() { CSliceUnref(data_); }
ChannelTrace::ChannelTrace(size_t max_event_memory)
: num_events_logged_(0),
event_list_memory_usage_(0),
max_event_memory_(max_event_memory),
head_trace_(nullptr),
tail_trace_(nullptr) {
if (max_event_memory_ == 0) {
return; }
gpr_mu_init(&tracer_mu_);
time_created_ = Timestamp::Now().as_timespec(GPR_CLOCK_REALTIME);
}
ChannelTrace::~ChannelTrace() {
if (max_event_memory_ == 0) {
return; }
TraceEvent* it = head_trace_;
while (it != nullptr) {
TraceEvent* to_free = it;
it = it->next();
delete to_free;
}
gpr_mu_destroy(&tracer_mu_);
}
void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
++num_events_logged_;
if (head_trace_ == nullptr) {
head_trace_ = tail_trace_ = new_trace_event;
}
else {
tail_trace_->set_next(new_trace_event);
tail_trace_ = tail_trace_->next();
}
event_list_memory_usage_ += new_trace_event->memory_usage();
while (event_list_memory_usage_ > max_event_memory_) {
TraceEvent* to_free = head_trace_;
event_list_memory_usage_ -= to_free->memory_usage();
head_trace_ = head_trace_->next();
delete to_free;
}
}
void ChannelTrace::AddTraceEvent(Severity severity, const grpc_slice& data) {
if (max_event_memory_ == 0) {
CSliceUnref(data);
return; }
AddTraceEventHelper(new TraceEvent(severity, data));
}
void ChannelTrace::AddTraceEventWithReference(
Severity severity, const grpc_slice& data,
RefCountedPtr<BaseNode> referenced_entity) {
if (max_event_memory_ == 0) {
CSliceUnref(data);
return; }
AddTraceEventHelper(
new TraceEvent(severity, data, std::move(referenced_entity)));
}
namespace {
const char* severity_string(ChannelTrace::Severity severity) {
switch (severity) {
case ChannelTrace::Severity::Info:
return "CT_INFO";
case ChannelTrace::Severity::Warning:
return "CT_WARNING";
case ChannelTrace::Severity::Error:
return "CT_ERROR";
default:
GPR_UNREACHABLE_CODE(return "CT_UNKNOWN");
}
}
}
Json ChannelTrace::TraceEvent::RenderTraceEvent() const {
char* description = grpc_slice_to_c_string(data_);
Json::Object object = {
{"description", Json::FromString(description)},
{"severity", Json::FromString(severity_string(severity_))},
{"timestamp", Json::FromString(gpr_format_timespec(timestamp_))},
};
gpr_free(description);
if (referenced_entity_ != nullptr) {
const bool is_channel =
(referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel ||
referenced_entity_->type() == BaseNode::EntityType::kInternalChannel);
object[is_channel ? "channelRef" : "subchannelRef"] = Json::FromObject({
{(is_channel ? "channelId" : "subchannelId"),
Json::FromString(absl::StrCat(referenced_entity_->uuid()))},
});
}
return Json::FromObject(std::move(object));
}
Json ChannelTrace::RenderJson() const {
if (max_event_memory_ == 0) {
return Json(); }
Json::Object object = {
{"creationTimestamp",
Json::FromString(gpr_format_timespec(time_created_))},
};
if (num_events_logged_ > 0) {
object["numEventsLogged"] =
Json::FromString(absl::StrCat(num_events_logged_));
}
if (head_trace_ != nullptr) {
Json::Array array;
for (TraceEvent* it = head_trace_; it != nullptr; it = it->next()) {
array.emplace_back(it->RenderTraceEvent());
}
object["events"] = Json::FromArray(std::move(array));
}
return Json::FromObject(std::move(object));
}
} }