/* * * Copyright 2017 gRPC authors. * * 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 #include "src/core/lib/channel/channel_trace.h" #include #include #include #include #include #include #include #include "src/core/lib/channel/status_util.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/error_utils.h" namespace grpc_core { namespace channelz { ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data, RefCountedPtr referenced_entity) : severity_(severity), data_(data), timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), 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, grpc_slice data) : severity_(severity), data_(data), timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME)), next_(nullptr), memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {} ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(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; // tracing is disabled if max_event_memory_ == 0 gpr_mu_init(&tracer_mu_); time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); } ChannelTrace::~ChannelTrace() { if (max_event_memory_ == 0) return; // tracing is disabled if max_event_memory_ == 0 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_; // first event case if (head_trace_ == nullptr) { head_trace_ = tail_trace_ = new_trace_event; } // regular event add case else { tail_trace_->set_next(new_trace_event); tail_trace_ = tail_trace_->next(); } event_list_memory_usage_ += new_trace_event->memory_usage(); // maybe garbage collect the tail until we are under the memory limit. 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, grpc_slice data) { if (max_event_memory_ == 0) { grpc_slice_unref_internal(data); return; // tracing is disabled if max_event_memory_ == 0 } AddTraceEventHelper(New(severity, data)); } void ChannelTrace::AddTraceEventWithReference( Severity severity, grpc_slice data, RefCountedPtr referenced_entity) { if (max_event_memory_ == 0) { grpc_slice_unref_internal(data); return; // tracing is disabled if max_event_memory_ == 0 } // create and fill up the new event AddTraceEventHelper( New(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"); } } } // anonymous namespace void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const { grpc_json* json_iterator = nullptr; json_iterator = grpc_json_create_child(json_iterator, json, "description", grpc_slice_to_c_string(data_), GRPC_JSON_STRING, true); json_iterator = grpc_json_create_child(json_iterator, json, "severity", severity_string(severity_), GRPC_JSON_STRING, false); json_iterator = grpc_json_create_child(json_iterator, json, "timestamp", gpr_format_timespec(timestamp_), GRPC_JSON_STRING, true); if (referenced_entity_ != nullptr) { const bool is_channel = (referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel || referenced_entity_->type() == BaseNode::EntityType::kInternalChannel); char* uuid_str; gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_entity_->uuid()); grpc_json* child_ref = grpc_json_create_child( json_iterator, json, is_channel ? "channelRef" : "subchannelRef", nullptr, GRPC_JSON_OBJECT, false); json_iterator = grpc_json_create_child( nullptr, child_ref, is_channel ? "channelId" : "subchannelId", uuid_str, GRPC_JSON_STRING, true); json_iterator = child_ref; } } grpc_json* ChannelTrace::RenderJson() const { if (max_event_memory_ == 0) return nullptr; // tracing is disabled if max_event_memory_ == 0 grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json_iterator = nullptr; if (num_events_logged_ > 0) { json_iterator = grpc_json_add_number_string_child( json, json_iterator, "numEventsLogged", num_events_logged_); } json_iterator = grpc_json_create_child( json_iterator, json, "creationTimestamp", gpr_format_timespec(time_created_), GRPC_JSON_STRING, true); // only add in the event list if it is non-empty. if (head_trace_ != nullptr) { grpc_json* events = grpc_json_create_child(json_iterator, json, "events", nullptr, GRPC_JSON_ARRAY, false); json_iterator = nullptr; TraceEvent* it = head_trace_; while (it != nullptr) { json_iterator = grpc_json_create_child(json_iterator, events, nullptr, nullptr, GRPC_JSON_OBJECT, false); it->RenderTraceEvent(json_iterator); it = it->next(); } } return json; } } // namespace channelz } // namespace grpc_core